上次我用 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 |
# 安裝 laravel
composer create-project --prefer-dist laravel/laravel laravel-vue "5.5.*"
# 安裝前端依賴包
npm install
安裝完之後,為了便於開發,使用熱更新模式。
# 在 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
php artisan make:migration news --create=news
# database/migrations/create_news.php
Schema::create('news', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('content');
$table->integer('is_recommend')->default(0);
$table->timestamps();
});
model
這裡使用命令生成 model
檔案,編輯對應的檔案內容。
php artisan make:model News
# app/News.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class News extends Model
{
public $fillable = ['title', 'content'];
}
controller
生成控制器,在控制器中定義三個介面對應的方法。
php artisan make:controller NewsController
# app/Http/Controllers/NewsController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\News;
class NewsController extends Controller
{
/**
* 推薦列表
*/
public function recommend()
{
$list = News::where('is_recommend', 1)->get();
foreach ($list as $key => $value) {
$list[$key]->created = $list[$key]->created_at->diffForHumans();
}
return $list;
}
/**
* 新聞列表
*/
public function index()
{
$list = News::get();
foreach ($list as $key => $value) {
$list[$key]->created = $list[$key]->created_at->diffForHumans();
}
return $list;
}
/**
* 新聞詳情
*/
public function show($id)
{
$row = News::findOrFail($id);
return $row;
}
}
router
定義 api
的介面路由,在 routes/api.php
檔案中定義。
# routes/api.php
Route::get('/news', 'NewsController@index');
Route::get('/news/recommend', 'NewsController@recommend');
Route::get('/news/{id}', 'NewsController@show');
到這裡我們準備工作已經完畢,接下來正式開發 Vue
的單頁應用,在開發單頁應用中,對應 Route
Api
Vuex
Components
這些,下面我們就來定義這些。
首先在首頁引入對應的 app.css
和 app.js
檔案。
# resource/vies/welcome.blade.php
<!DOCTYPE html>
<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
例項,初始化和載入所需的元件。
# 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 個路由,如下
# 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
集中式儲存管理應用的所有元件的狀態,這裡使用的是多模組方式記錄資料。
# 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
包來請求資料,具體用法參考文件。
# 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
定義元件的方式參考文件。
三個頁面的具體寫法定義如下:
# 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
可以熱更新,實時看到頁面的變化。
文章地址
本作品採用《CC 協議》,轉載必須註明作者和本文連結