上次我用 laravel5.3 + Vue
开发了一个简单的单页应用,这次我打算将其升级到 laravel5.5
,在升级的过程中,做一下记录,其源码放在 github
上面,源码地址
开发环境
软件包 | 版本 |
---|---|
Laravel | 5.5 |
Vue | > 2.5.7 |
axios | > 0.17 |
vue-router | > 3.0.1 |
vuex | > 3.0.1 |
安装
1 | # 安装 laravel |
安装完之后,为了便于开发,使用热更新模式。1
2
3
4
5
6
7
8
9
10# 在 webpack.mix.js 中添加配置
mix.browserSync({
proxy: 'localhost:8000'
});
# 执行 `php artisan serve`
php artisan serve
# 执行 npm run watch
npm run watch
打开浏览器访问 http://localhost:3000
就可以看到 laravel
的欢迎页面了
目标
开发三个页面,首页,列表,详情,相对应准备 3 个 api
接口
migration
1 | php artisan make:migration news --create=news |
1 | # database/migrations/create_news.php |
model
这里使用命令生成 model
文件,编辑对应的文件内容。1
php artisan make:model News
1 | # app/News.php |
controller
生成控制器,在控制器中定义三个接口对应的方法。1
php artisan make:controller NewsController
1 | # app/Http/Controllers/NewsController |
router
定义 api
的接口路由,在 routes/api.php
文件中定义。1
2
3
4# routes/api.php
Route::get('/news', 'NewsController@index');
Route::get('/news/recommend', 'NewsController@recommend');
Route::get('/news/{id}', 'NewsController@show');
Vue单页
到这里我们准备工作已经完毕,接下来正式开发 Vue
的单页应用,在开发单页应用中,对应 Route
Api
Vuex
Components
这些,下面我们就来定义这些。
首先在首页引入对应的 app.css
和 app.js
文件。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25# resource/vies/welcome.blade.php
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="csrf-token" content="@{{ csrf_token }}">
<title>Laravel & Vue</title>
<link rel="stylesheet" type="text/css" href="/css/app.css">
</head>
<body>
<div id="app">
<nav class="navbar navbar-inverse">
<div class=" container">
<div class="navbar-header">
<a class="navbar-brand" href="/">LaravelVue</a>
</div>
</div>
</nav>
<div class="container main">
<router-view />
</div>
</div>
<script type="text/javascript" src="/js/app.js"></script>
</body>
</html>
配置启动 app.js
应用对应的入口文件是 app.js,所以在这个入口文件中,我们实例化 Vue
实例,初始化和加载所需的组件。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# resource/assets/js/app.js
require('./bootstrap');
window.Vue = require('vue');
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import store from './store/'; // vuex 数据存储所需对象
import routes from './routes'; // 路由配置文件
// 实例化路由
const router = new VueRouter({
routes
})
var vm = new Vue({
store,
router
}).$mount('#app');
路由
前端页面主要有 3 个路由,如下1
2
3
4
5
6
7# resource/assets/js/routes.js
export default[
{ path: '', redirect: '/index' },
{ path: '/index', component: require('./page/App.vue') },
{ path: '/list', component: require('./page/List.vue') },
{ path: '/detail/:id', component: require('./page/Detail.vue') }
];
Vuex
Vuex
集中式存储管理应用的所有组件的状态,这里使用的是多模块方式记录数据。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52# resource/assets/js/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import news from './news';
Vue.use(Vuex);
export default new Vuex.Store({
// 可以设置多个模块
modules: {
news
}
});
# resource/assets/js/store/news.js
import api from '../api';
export default{
state: {
recommend: [], // 推荐
lists: [], // 列表
detail: {} // 详情
},
mutations: {
// 注意,这里可以设置 state 属性,但是不能异步调用,异步操作写到 actions 中
SETRECOMMEND(state, lists) {
state.recommend = lists;
},
SETLISTS(state, lists) {
state.lists = lists;
},
SETDETAIL(state, detail) {
state.detail = detail;
}
},
actions: {
getNewsDetail({commit}, id) {
// 获取详情,并调用 mutations 设置 detail
api.getNewsDetail(id).then(function(res) {
commit('SETDETAIL', res.data);
document.body.scrollTop = 0;
});
},
getNewsRecommend({commit}) {
api.getNewsRecommend().then(function(res) {
commit('SETRECOMMEND', res.data);
});
},
getNewsLists({commit}) {
api.getNewsLists().then(function(res) {
commit('SETLISTS', res.data);
});
}
}
}
api
我们在这里定义前端请求数据 api
,这里使用的是 axios
包来请求数据,具体用法参考文档。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# resource/assets/js/api.js
import axios from 'axios'
export default {
// 首页推荐接口
getNewsRecommend: function (params) {
return axios.get('api/news/recommend', {
params: params
})
},
// 列表接口
getNewsLists: function (params) {
return axios.get('api/news', {
params: params
})
},
// 详情接口
getNewsDetail: function (id) {
return axios.get('api/news/' + id)
}
}
page
我们在这里定义组件页面,将其页面放到 page
目录下面,Vue
定义组件的方式参考文档。
三个页面的具体写法定义如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110# resource/assets/js/page/App.vue
<template>
<div class="panel panel-default">
<div class="panel-heading">新闻推荐
<router-link to="/list" class="pull-right">更多</router-link>
</div>
<ul class="list-group">
<li class="list-group-item"
v-for="row in recommend">
<router-link :to="{path:'/detail/' + row.id}">
{{ row.title }}
</router-link>
<span class="pull-right">{{ row.created }}</span>
</li>
</ul>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default({
// 映射 vuex 上面的属性
computed: mapState({
recommend: state => state.news.recommend
}),
created() {
// 获取推荐列表
this.getNewsRecommend();
},
methods: {
// 映射 vuex 对象上的方法
...mapActions([
'getNewsRecommend'
])
}
});
</script>
# resource/assets/js/page/List.vue
<template>
<div class="panel panel-default">
<div class="panel-heading">新闻列表</div>
<ul class="list-group">
<li class="list-group-item"
v-for="row in lists">
<router-link :to="{path:'/detail/' + row.id}">
<span class="label label-success" v-if="row.is_recommend">推荐</span>
{{ row.title }}
</router-link>
<span class="pull-right">{{ row.created }}</span>
</li>
</ul>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default({
computed: mapState({
lists: state => state.news.lists
}),
created() {
this.getNewsLists();
},
methods: {
...mapActions([
'getNewsLists'
])
}
});
</script>
# resource/assets/js/page/Detail.vue
<template>
<div>
<ol class="breadcrumb">
<li><a href="/">首页</a></li>
<li><router-link to="/list" class="pull-right">新闻</router-link></li>
<li class="active">{{ detail.title }}</li>
</ol>
<h3><span class="label label-success" v-if="detail.is_recommend">推荐</span> {{ detail.title }}</h3>
<p>创建时间:{{ detail.created_at }}</p>
<div>
{{ detail.content }}
</div>
</div>
</template>
<style>
.breadcrumb{
padding: 8px 0;
}
</style>
<script>
import { mapState, mapActions } from 'vuex';
export default({
computed: mapState({
detail: state => state.news.detail
}),
created() {
// 获取路由参数id
// js 中用 this.$route 获取当前路由,用 this.$router 获路由对象,全部路由信息
// 在模板中用 $router 和 $router 直接调用
var id = this.$route.params.id;
this.getNewsDetail(id);
},
methods: {
...mapActions([
'getNewsDetail'
])
}
});
</script>
这里我们简单的单页应用就开发完毕了,使用 npm run watch
可以热更新,实时看到页面的变化。
©版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 & 作者信息。
Happly Coding