[Express+Vue 搭建電商網站] 02 - vue-router 的使用

vue-router 的使用

在這篇學到的事情:

  • vue-router 的使用方法與學習路由基礎知識

建立新組件

首先我們要先建立新的頁面組件,新建一個 src/components/Home.vue 檔案

<template>
 <div>
 <div class="title">
 <h1>{{msg}}</h1>
 </div>
 </div>
</template>
<script>
 export default {
 name: 'home',
 data () {
 return {
 msg: 'Welcome to Your Vue.js App'
 };
 },
 }
</script>

看起來跟一開始預設的 HelloWorld.vue 有 87% 像,但是這邊先不對樣式做糾結,之後再去找 UI 庫套用

設定 vue-router

在安裝了 vue-router 之後,會發現專案中多了一個資料夾 /src/router/index.js,這就是 vue-router 的設定檔
藉由以下這段我們發現,路徑 '/' 使用的是 Home 這個組件

const 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')
 }
]

順著邏輯往上找會發現 Home 這個組件的引用來源

import Home from '../views/Home.vue'

接著打開 /views/Home.vue,原來這引入了 HelloWorld 組件

<template>
 <div class="home">
 <img alt="Vue logo" src="../assets/logo.png">
 <HelloWorld msg="Welcome to Your Vue.js App"/>
 </div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
 name: 'Home',
 components: {
 HelloWorld
 }
}
</script>

知道原理之後呢,就把 /views/Home.vue 內部目前沒有用到的部分刪除,並且換成我們上面建立的 Home 組件

<script>
// @ is an alias to /src
import Home from '@/components/Home.vue'
export default {
 name: 'Home',
 components: {
 Home
 }
}
</script>

這時候使用瀏覽器開啟專案首頁,應該就會看到首頁已經變成 Home.vue 的內容

加入頁面上方導航超連結

打開 App.vue 檔案,在 id="app" 中加入三個 router-link 標籤的超連結,這是 Vue Router 的 API
根據官網說明 <router-link> 比起寫死的 <a href="..."> 會好一些

  • 無論是 HTML5 history 模式還是 hash 模式,它的表現行為一致,所以,當你要切換路由模式,或者在 IE9 降級使用 hash 模式,無須作任何變動。
  • 在 HTML5 history 模式下,router-link 會守衛點擊事件,讓瀏覽器不再重新加載頁面。
  • 當你在 HTML5 history 模式下使用 base 選項之後,所有的 to 屬性都不需要寫 (基路徑) 了。
<template>
 <div id="app">
 <nav>
 <div class="container">
 <ul class="nav__left">
 <li>
 <router-link to="/">Home</router-link>
 </li>
 <li>
 <router-link to="/admin">Admin</router-link>
 </li>
 <li>
 <router-link to="/cart">Cart</router-link>
 </li>
 </ul>
 </div>
 </nav>
 <router-view/>
 </div>
</template>

看到上面的程式碼內容,聰明的你一定知道接著我們要建立三個頁面

  1. admin 後台管理
  2. 購物車頁面
    剛剛示範了怎麼在 /views/Home.vue 中引入 src/components/Home.vue,但在這邊先簡單一點,直接在 /views/ 目錄下建立如同 src/components/Home.vue 內容的檔案
    這時候 /views/ 資料夾應該會長得像這樣

folder-tree
這時候其實可以把剛剛的 Home.vue 搬移進 /views/ 中,我們原本的引用在這邊有點多此一舉了。但是在搬移過後會發現瀏覽器提示我們發生了一些問題,原來是 Home.vue 找不到檔案,但是為什麼呢?我們不是在 vue-router 裡面指定路徑 '/‘ 要到 Home.vue 嗎?
首先復原程式碼,來看看在哪裡使用到了 src/components/Home.vue
哈!原來是一開始我們創建新組建時候把 App.vue 裡面的初始頁面 import 設定成 Home。這也就說明了為什麼在 admin 以及 Cart 頁面中 Home.vue 的內容還是陰魂不散。在刪除 import 的內容之後一切就正常了

新建立的頁面加入路由

接著把剛剛新建的頁面加入路由設定檔案 /src/router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/views/Home.vue'
import Admin from '@/views/Admin';
import Cart from '@/views/Cart';
Vue.use(Router)
const routes = [
 {
 path: '/',
 name: 'Home',
 component: Home
 },
 {
 path: '/admin',
 name: 'Admin',
 component: Admin
 },
 {
 path: '/cart',
 name: 'Cart',
 component: Cart,
 },
]
const router = new Router({
 routes
})
export default router

好像有些什麼東西怪怪的?為什麼可以用 @ 引用東西呢?代表什麼意思?
在我深入研究後發這是一個 webpack 的設定,存在於 \node_modules\@vue\cli-service\lib\config\base.js,進入檔案之後可以發現有設定了一個 alias set('@', api.resolve('src')) 這代表告訴了 vue

看到路徑用 @ 開頭的,就從 src 這個目錄開始操作
這樣做可以大幅度的減少我們使用 ../ 這種作法造成目錄結構變換就專案大爆炸,或是為了存取深層的檔案,畫面被一堆點點斜線佔滿
在完成了以上動作之後,打開瀏覽器預覽一下

router-demo
看來我們剛剛完成了一個簡單的基於 Vue 的多頁面網站了!

嵌套路由

有點經驗的工程師就知道,路由絕對不是這麼簡單的。當頁面少的時候可以全塞在一隻檔案裡面,但當頁面開始多這樣就會顯得很亂,並且無法一眼看出彼此之間的階層關聯。還好 vue-router 提供了嵌套路由的功能,讓我們可以組織化的管理相關聯的頁面
在後台頁面中會使用到很多操作的頁面,例如新增、修改商品,下面就藉由嵌套路由的方法來管理這些路由
在引入的地方加入我們之後要增加的頁面,這邊只是先聲明,之後會一步一步的完成頁面

// Admin Components
import Index from '@/views/admin/Index'
import New from '@/views/admin/New'
import Products from '@/views/admin/Products'
import Edit from '@/views/admin/Edit'

路由常數中加入嵌套路由,會發現 Admin 下有四個組件(component),而嵌套路由會為相關連的子路由設置一個入口頁面,然後把這些頁面都放到 children 定義中的陣列中。

 {
 path: '/admin',
 name: 'Admin',
 component: Index,
 children: [
 {
 path: '',
 name: 'Products',
 component: Products,
 },
 {
 path: 'new',
 name: 'New',
 component: New,
 },
  
 {
 path: 'edit/:id',
 name: 'Edit',
 component: Edit,
 },
 ]
 },

接著回到 /src/views/admin 建立

  • Index.vue
  • Edit.vue
  • New.vue
  • Products.vue

Index.vue

Index 是我們上面提到的入口組件,也就是渲染 path = /admin 的基礎組件,其餘的組件藉由 children 陣列宣告為嵌套的子路由。在子路由內的路由,前端都必須加上父層的路徑。而在上方的定義中,我們把 /admin/ 的渲染子組件定義給了 Products

<template>
 <div>
 <div class="admin-new">
 <div class="container">
 <div class="col-lg-3 col-md-3 col-sm-12 col-xs-12">
 <ul class="admin-menu">
 <li>
 <router-link to="/admin">View Products</router-link>
 </li>
 <li>
 <router-link to="/admin/new">New Products</router-link>
 </li>
 </ul>
 </div>
 <router-view></router-view>
 </div>
 </div>
 </div>
</template>

<router-view></router-view> 是用來渲染子路由的組件,比如說我們進入了 admin/new 那麼 <router-view></router-view> 內部會被替換成 New.vue 組件的內容,因為我們在上面路由定義中定義 ‘/new’ 的路由渲染組件是 New.vue

Edit.vue

<template>
 <div>
 <div class="title">
 <h1>This is Admin/Edit/{{$route.params.id}}</h1>
 </div>
 </div>
</template>

Edit 這個路由在剛剛路由定義的時候有點不一樣,他的路徑是 edit/:id 這種寫法被稱作動態路由。:id 會接收任意的內容作為一個參數傳入。例如我們進入 /admin/edit/banana 頁面,那麼就可以在 Edit.vue 這個組件上使用

{{$route.params.id}}

來呼叫到 :id 接收到的值,在上面的例子中就是「banana」

New.vue

<template>
 <div>
 <div class="title">
 <h1>This is Admin/New</h1>
 </div>
 </div>
</template>

Products.vue

<template>
 <div>
 <div class="title">
 <h1>This is Admin</h1>
 </div>
 </div>
</template>

建立完成之後就完成了嵌套路由的應用

留言