延續昨天的主題 Vuetify 中用到的技術大方向有:
接下來幾天會利用 Vuetify 的 WebpackSSR 模板,邊解釋邊學習上面這些東西,搞定這些技術後,就擁有了一個完整的開發流程了。
先從 vue-router 開始!
我們可以簡單的透過 Vue.js + vue-router 來建立一個 Single Page Application(SPA)。
經過了前面對 Vue.js 的學習,已經可以透過元件(Component)來組合應用程式。
而當我們想要將 vue-router 加入專案時,我們需要將元件映射到路由(routes),然後告訴 vue-router 在何處渲染。
先看一個基本的使用 vue-router 的範例:
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<router-view></router-view>
</div>
const Foo = { template: '<div>foo</div>' };
const Bar = { template: '<div>bar</div>' };
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
];
const router = new VueRouter({
routes
});
const app = new Vue({
router
}).$mount('#app');
附上 codepen 連結 (https://codepen.io/hunterliu1003/pen/ZvyJrM)
看完簡單範例後,回到 Vuetify 的模板 WebpackSSR(可先回上一篇看快速開始的教學)。
附上 WebpackSSR 的目錄結構,方便對照:
在 Vuetify WebpackSSR(以下簡稱VW)的目錄結構中,所有關於 vue-router 的東西都放在 router
資料夾。透過router
中的index.js建立createRouter,並在assets
中的app.js引入,並且將實體化的Router物件作為屬性傳入 Vue instance 中。
看一下程式碼的片段(如果想看到結果請依照上一篇的懶人包安裝):
程式碼解釋的部分就直接寫在註解,因為想不到更好的方式,程式碼一多為了避免失焦就這樣子吧。
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
const meta = require('./meta.json')
// meta.json 中用json格式定義了所有的路由的 meta 標籤。
// 切換頁面時,html中的meta標籤內容會根據 meta.json 中的設定更新。
function route (path, view) {
return {
path: path,
// 網址列上的路徑
meta: meta[path],
// 根據該路徑(path)的meta屬性設定為meta.json中所屬的路由物件
component: resolve => import(`pages/${view}View.vue`).then(resolve)
// 這裡引入的.vue檔是指資料夾pages中的Single File Component。
// 資料夾components中放的則不需要是用 v-layout 包覆的自定義元件。
}
}
Vue.use(Router)
// 使用 plugin 的方法,可參考(https://vuejs.org/v2/guide/plugins.html#Using-a-Plugin)
export function createRouter () {
const router = new Router({
base: __dirname,
mode: 'history',
scrollBehavior: () => ({ y: 0 }),
routes: [
route('/', 'Welcome'),
route('/inspire', 'Inspire'),
{ path: '*', redirect: '/' }
]
// routes 定義所有的路由,此處只有'/'和'/inspire'兩個頁面
// { path: '*', redirect: '/' } 是為了處理未定義的路由,將頁面導到首頁(/)。
})
router.beforeEach((to, from, next) => {
if (typeof ga !== 'undefined') {
ga('set', 'page', to.path)
ga('send', 'pageview')
}
next()
}) // google analytics 可略過。
return router
}
assets/app.js
import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.css'
import App from './App.vue'
import Components from 'components/_index'
import { createStore } from 'store/index'
import { createRouter } from 'router/index'
import { sync } from 'vuex-router-sync'
Vue.use(Vuetify)
Object.keys(Components).forEach(key => {
Vue.component(key, Components[key])
})
export function createApp (ssrContext) {
const store = createStore() // 實體化 vuex 下篇回提到
const router = createRouter() // 實體化 router = new Router({options})
sync(store, router)
// 透過 vuex-router-sync 同步 vuex 和 vue-router,會同步的屬性有 {
// path: '',
// query: null,
// params: null
// }
// 主要是將 vue-router 的狀態放進 vuex 的 state 中,透過改變 state 進行路由的操作。
// 這使我們可以輕鬆透過以下方法取得或操作路由設定:
// store.state.route.path // current path (string)
// store.state.route.params // current params (object)
// store.state.route.query // current query (object)
const app = new Vue({
router,
store,
ssrContext, // 之後篇幅會補充
render: h => h(App)
// h => h(App)中的App為資料夾assets中的App.vue,App.vue是這整個SPA最核心基礎的頁面組成。
})
// 將 router, store, ssrContext, render 傳入選項物件中
return { app, router, store }
}