Byte Ebi's Logo

Byte Ebi 🍤

每天一小口,蝦米變鯨魚

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

使用 Express + Vue 搭建一個電商網站 - vue-router 的使用

Ray

在接下來的內容中會學習 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>

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


專案範例程式碼 GitHub 網址:ray247k/mini-E-commerce

最新文章

Category

Tag