Laravel + Vue 开发单页应用

开发环境:
Homestead + Laravel5.3 + vue2 + vue-resource1 + vue-router2 + vuex2

源码放在 github 上面,源码地址

环境安装就不做介绍了,由于 5.3 自带 vue2vue-resource,但是需要安装 vue-routevuex
package.json 中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
"devDependencies": {
"bootstrap-sass": "^3.3.7",
"extract-text-webpack-plugin": "^2.0.0-beta.4",
"gulp": "^3.9.1",
"jquery": "^3.1.0",
"laravel-elixir": "^6.0.0-9",
"laravel-elixir-vue-2": "^0.2.0",
"laravel-elixir-webpack-official": "^1.0.2",
"lodash": "^4.16.2",
"vue": "^2.0.1",
"vue-resource": "^1.0.3",
// 添加
"vue-router": "^2.0.1",
"vuex": "^2.0.0"
}
...

执行 npm install 安装

介绍下开发的需求,主要有三个页面:

  1. 首页展示推荐新闻
  2. 新闻列表
  3. 新闻详情

入口文件 app.js

resources/asserts/js/app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import Vue from 'vue';

import VueResource from 'vue-resource';
Vue.use(VueResource);
import VueRouter from 'vue-router';
Vue.use(VueRouter);

import store from './store/'; // vuex 数据存储所需对象

import routes from 'routes'; // 路由配置文件

// 实例化路由
const router = new VueRouter({
routes
});

// 实例化 Vue
var vm = new Vue({
store,
router
}).$mount('#app');

数据vuex

vuex 我们使用多模块的开发模式,这在项目中设计十分有必要的,如果把所有的数据一个实例上面,管理显得还是十分的混乱。
resources/asserts/store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
import Vue from 'vue';
import Vuex from 'vuex';
import news from './news';

Vue.use(Vuex);

export default new Vuex.Store({
// 可以设置多个模块
modules: {
news
}
});

书写 news 模块代码
resources/asserts/store/news.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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import api from '../api';   // 主要是异步调用接口文件,下面有介绍

export default{
state: {
recommend: [], // 存储推荐列表
lists: [], // 存储列表
detail: {} // 存储详情
},
mutations: {
// 注意,这里可以设置 state 属性,但是不能异步调用,异步操作写到 actions 中
SETRECOMMEND(state, recommend) {
state.recommend = recommend;
},
SETLISTS(state, lists) {
state.lists = lists;
},
SETDETAIL(state, detail) {
state.detail = detail;
}
},
actions: {
GETDETAIL({commit}, id) {
// 获取详情,并调用 mutations 设置 detail
api.getNewsDetail(id).then(function(res) {
commit('SETDETAIL', res.data);
document.body.scrollTop = 0;
});
},
GETRECOMMEND({commit}) {
// 获取推荐,并调用 mutations 设置 recommend
api.getNewsRecommend().then(function(res) {
commit('SETRECOMMEND', res.data);
});
},
GETLISTS({commit}) {
// 获取列表,并调用 mutations 设置 lists
api.getNewsLists().then(function(res) {
commit('SETLISTS', res.data);
});
}
}
};

看到上面的代码中引入了 api ,我将接口的请求全部放到 api.js 中,便于管理,其实这里也可以分成模块。
resources/asserts/api.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
26
import Vue from 'vue';
import VueResource from 'vue-resource';
Vue.use(VueResource);

// 设置 Laravel 的 csrfToken
Vue.http.interceptors.push((request, next) => {
request.headers.set('X-CSRF-TOKEN', Laravel.csrfToken);
next();
});

const API_ROOT = ''; // 可以根据自己的开发环境设置

export default({
// 首页推荐信息
getNewsRecommend: function() {
return Vue.resource(API_ROOT + '/news').get();
},
// 列表信息
getNewsLists: function() {
return Vue.resource(API_ROOT + '/newslist').get();
},
// 详情
getNewsDetail: function(id) {
return Vue.resource(API_ROOT + '/newsdetail/' + id).get();
}
});

路由信息 routes.js

resources/asserts/js/routes.js

1
2
3
4
5
6
export default[
{ path: '', redirect: '/index' },
{ path: '/index', component: require('./page/App.vue') },
{ path: '/newslist', component: require('./page/List.vue') },
{ path: '/newsdetail/:id', component: require('./page/Detail.vue') }
];

组件 App.vue

resources/asserts/js/page/App.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
<template>
<div>
<h3>首页推荐</h3>
<ul class="list-group">
<li class="list-group-item"
v-for="row in recommend">
<router-link :to="{path:'/newsdetail/' + row.id}">
{{ row.title }}
</router-link>
<li class="list-group-item">
<router-link to="/newslist">更多</router-link>
</li>
</li>
</ul>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default({
// 映射 vuex 上面的属性
computed: mapState({
recommend: state => state.news.recommend
}),
created() {
// 获取推荐列表
this.GETRECOMMEND();
},
methods: {
// 映射 vuex 对象上的方法
...mapActions([
'GETRECOMMEND'
])
}
});
</script>

组件 List.vue

resources/asserts/js/page/List.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
<template>
<div>
<h3>列表信息</h3>
<ul class="list-group">
<li class="list-group-item"
v-for="row in lists">
<router-link :to="{path:'/newsdetail/' + row.id}">
{{ row.title }}
</router-link>
</li>
</ul>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default({
computed: mapState({
lists: state => state.news.lists
}),
created() {
this.GETLISTS();
},
methods: {
...mapActions([
'GETLISTS'
])
}
});
</script>

组件 Detail.vue

resources/asserts/js/page/Detail.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
<template>
<div>
<table class="table table-bordered">
<tr>
<td width="20%">ID</td>
<td>{{ detail.id }}</td>
</tr>
<tr>
<td width="20%">标题</td>
<td>{{ detail.title }}</td>
</tr>
<tr>
<td width="20%">内容</td>
<td>{{ detail.content }}</td>
</tr>
<tr>
<td width="20%">创建时间</td>
<td>{{ detail.created_at }}</td>
</tr>
</table>
</div>
</template>
<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.GETDETAIL(id);
},
methods: {
...mapActions([
'GETDETAIL'
])
}
});
</script>

模板文件

resources/views/welcome.blade.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<title>Laravel</title>
</head>
<body>
<div id="app" class="container"><router-view class="view"></router-view>
</div>
</body>
<script type="text/javascript">
var Laravel = {
// 设置 csrfToken
csrfToken: '{{ csrf_token() }}'
};
</script>
<script src="/js/app.js"></script>
</html>

服务端 API

服务端的 api 只是一个数据的模拟,没有做深入的开发
routes/web.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Route::get('/news', function() {
return [
['id' => 1, 'title' => 'new1'],
['id' => 2, 'title' => 'new2'],
['id' => 3, 'title' => 'new3'],
['id' => 4, 'title' => 'new4'],
];
});
Route::get('/newslist', function() {
return [
['id' => 1, 'title' => 'new1'],
['id' => 2, 'title' => 'new2'],
['id' => 3, 'title' => 'new3'],
['id' => 4, 'title' => 'new4'],
];
});
Route::get('/newsdetail/{id}', function($id) {
return [
'id' => 1,
'title' => 'news',
'content' => 'content',
'created_at' => date('Y-m-d H:i:s')
];
});

运行

1
2
php artisan serve   // 开启 web
gulp // 打包前端资源,开发的时候用 gulp watch 监听实时浏览

打开浏览器,访问 http://localhost:8000 查看效果。

这个例子只是简单的使用了 Laravelvue,详细开发请查看官方文档。

©版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 & 作者信息

End

坚持原创技术分享,您的支持将鼓励我继续创作!
Flyertutor WeChat Pay

WeChat Pay

Flyertutor Alipay

Alipay