iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 20
0
Modern Web

用範例理解 Vue.js系列 第 20

用範例理解 Vue.js #20:vue-router in Vuetify

Imgur

圖片來源

延續昨天的主題 Vuetify 中用到的技術大方向有:

  • vue-router
  • vuex
  • vue-server-renderer
  • webpack
  • express

接下來幾天會利用 Vuetify 的 WebpackSSR 模板,邊解釋邊學習上面這些東西,搞定這些技術後,就擁有了一個完整的開發流程了。

先從 vue-router 開始!

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)

vue-router in Vuetify template WebpackSSR

看完簡單範例後,回到 Vuetify 的模板 WebpackSSR(可先回上一篇看快速開始的教學)。

附上 WebpackSSR 的目錄結構,方便對照:

  • projectName
    • assets
    • build
    • components
    • mixins
    • pages
    • router
    • static
    • store

在 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 }
}

參考資料


上一篇
用範例理解 Vue.js #19:Vuetify
下一篇
用範例理解 Vue.js #21:Vuex in Vuetify
系列文
用範例理解 Vue.js30

尚未有邦友留言

立即登入留言