點燈坊

失くすものさえない今が強くなるチャンスよ

Vue Router 基礎概念

Sam Xiao's Avatar 2019-06-17

Vue 雖然由 Component 所構成,為了模擬出不同頁面有不同網址,Vue 官方也提供了 Vue Router,這是前端自己的 Route,有別於後端的 Route。

Version

macOS Mojave 10.14.5
Node 12.4.0
Vue CLI 3.8.4
Vue 2.6.10
Vue-router 3.0.3

Add Vue-Router

Vue CLI 已經整合 Vue Router,可以直接建立含有 Vue Router 的 project。

$ vue create vue-router-basic

basic000

使用 Vue CLI 的 vue create 建立 vue-router-basic

basic001

Vue Router 雖然為官方 package,但預設並沒有包含在 Vue 內,因此需要選擇 Manually select features 另外安裝。

basic002

除了預設的 BabelLinter / Formatter 外,使用 space bar 選擇 Router

basic003

History Mode 選擇 n

至於什麼是 History Mode ? 在 Vue Router 之 History Mode 有詳細討論

basic004

選擇 ESLint with error prevention only

basic005

選擇 Lint on save

basic006

選擇 In dedicated config files,也就是 Babel、PostCSS、ESLint … 等工具都有自己的 config 檔,而不會全部集中在 package.json

basic007

Save this as a preset for future projects 選擇 n,也就是預設不使用 Vue Router。

basic008

成功建立含有 Vue Router 的 project。

basic009

package.json 可以看到 "vue-router" : "^3.0.3",表示 vue-router 已經安裝成功。

$ yarn serve

basic010

在專案目錄下輸入 yarn serve 啟動 Vue CLI 內建的 web server。

basic011

Vue 內建 web server 預設啟動在 http://localhost:8080

basic012

  1. Home 的 route 為 /
  2. 與 Vue 預設專案不同,已經多了 HomeAbout

basic013

  1. About,則進入了 About page
  2. About 的 route 為 /about

Architecture

rounter.js

import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
});

與一般 Vue 專案不同,在 src 目錄下多了route.js,為統一設定 route 之處。

第 2 行

import Router from 'vue-router';

importvue-router 的 class,並自己取名為 Router

此為 ES6 的 default export,因此可自行命名

第 5 行

Vue.use(Router);

Vue 規定若 package 要供 Vue 使用,則可使用 Vue.use() 傳進 package 的 class、object 或 function。

第 7 行

export default new Router({

這相當於

let router = new Router();
export default router;

只是 Vue 將兩行寫成一行,將 Router object 使用 defaul export。

第 8 行

routes: [

routes 為 property,將 route 以陣列設定。

第 9 行

{
  path: '/',
  name: 'home',
  component: Home,
},
  • path : 設定 route path
  • name : 設定 route 的名稱
  • component : 設定 route 所使用的 component

由於 Vue 是基於 component 與 SPA 架構,換 route 只是換 component 而已

14 行

{
   path: '/about',
   name: 'about',
   // route level code-splitting
   // this generates a separate chunk (about.[hash].js) for this route
   // which is lazy-loaded when the route is visited.
   component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
},

若要使 component 有 lazy loading 效果,也就是不要將該 component 包在 chunk-vendors.[hash].js 內,而是另外獨立的 .js,只有當該 route 真正被執行時,才會下載 route.[hash].js

/* webpackChunkName: "about" */ 並非註解,而是給 Webpack 看的,可以省略,會自動以 hash 值作為檔名,實務上建議與 route 名稱相同,可藉此觀察 Webpack 是否正確啟動 lazy loading

main.js

import Vue from 'vue';
import App from './App.vue';
import router from './router';

Vue.config.productionTip = false;

new Vue({
  router,
  render: h => h(App),
}).$mount('#app');

第 3 行

import router from './router';

將自己 router.js import 進來,不是 vue-router

第 7 行

new Vue({
  router,
  render: h => h(App),
}).$mount('#app');

router 傳進 Vue instance。

App.vue

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>

第 4 行

<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>

若要使用 Vue Router 所定義的 route,不能再使用 <a/>,而要改用 Vue 所提供的 <router-link/> component,並使用 to directive 指定 route。

第 7 行

<router-view/>

<routr-view/> 為 component 的 place holder,將來改變 route,component 的切換就是在 <router-view/>

Build Target

實際執行 yarn build,看看 Vue Route 如何支援 lazy loading。

$ yarn build

basic014

在專案目錄下輸入 yarn build 將整個專案編譯打包到 dist 目錄下。

basic015

chunk-vendors.*.js:在 node_modules 所使用的 package,如 Vue、Vue Router、Axios 會被編譯在此。

app.*.js:Root component app.vue 被編譯在此。

about.*.jsAbout.vue 被編譯在此。

也就是當執行首頁時,只會載 chunk-vendors.*.jsapp.*.js,只有當 about 被點擊時,才會下載 about.*.js,如此可加速首頁下載速度

yarn build 所產生的檔案皆放在 dist 目錄下,將這些檔案全部搬到 web server 即可。

Deployment

Vue CLI 預設沒有提供 dist 目錄下的 web server,需另外安裝 package。

$ yarn global add serve

basic016

安裝 serve package 於 global。

basic017

安裝 serve package 完成。

$ serve dist

basic018

在專案目錄下輸入 serve dist,其中 dist 為目錄名稱,因為 yarn build 所產生的檔案皆放在 dist 目錄下。

basic019

servedist 目錄啟動在 http://localhost:5000

basic020

http://localhost:5000 成功執行 Vue。

Conclusion

  • Vue CLI 已經將 Vue Router 整進來,讓我們可快速建立 route
  • Vue Router 支援 lazy loading,可將 component 分別打包在個別的 .js,增加首頁下載速度
  • 若要執行 dist 目錄下的檔案,要另外安裝 serve 套件
  • yarn serveserve dist 雖然都能執行,但原理不同;yarn serve 是執行 src 目錄下的 JavaScript,而 serve dist 是執行 dist 目錄下的 JavaScript

Sample Code

完整範例可在我的 GitHub 上找到

Reference

Vue Router, Getting Started