iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
Vue.js

業主說給你30天學會Vue系列 第 26

V26_Vue的Routing的操作

  • 分享至 

  • xImage
  •  

V26_Vue的Routing的操作

今天來研究一下Vue的Routing的操作,
在一般的Vue的學習上,有使用SFC或是Component的方式
也有使用slot來切撤不同的內容
不過都是基於單一的網頁或是路徑

如果想要以不同的網址路徑來切換不同的內容的話
就要使用到Routing的功能了

先來參考W3School的說明
Vue Routing
https://www.w3schools.com/vue/vue_routing.php

首先有提到Routing的需求,與Dynamic Components的想法類似
先來了解一下 Dynamic Components

參考W3School的介紹
https://www.w3schools.com/vue/vue_dynamic-components.php

快速的來看一下範例
main.js

import { createApp } from 'vue'

import App from './App.vue'
import CompOne from './components/CompOne.vue'
import CompTwo from './components/CompTwo.vue'

const app = createApp(App)
app.component('comp-one', CompOne)
app.component('comp-two', CompTwo)
app.mount('#app')

這個OK,
會引入 2個元件 <comp-one>, <comp-two>

App.vue

<template>
  <h1>Dynamic Components</h1>
  <p>App.vue switches between which component to show.</p>
  <button @click="toggleValue = !toggleValue">Switch component</button>
  <component :is="activeComp"></component>
</template>

<script>
  export default {
    data () {
      return {
        toggleValue: true
      }
    },
    computed: {
      activeComp() {
        if(this.toggleValue) {
          return 'comp-one'
        }
        else {
          return 'comp-two'
        }
      }
    }
  }
</script>

為了達到動態切換component的目的
使用 <component :is="activeComp"></component> 的語法

:is 屬性用來切換不同的元件,同時綁定到 activeComp

activeComp 是一個 computed 的函式,
執行 根據 this.toggleValue 的狀態,回傳 'comp-one'或'comp-two'
來切換 <component>的內容

按下 <button @click="toggleValue = !toggleValue">Switch component</button>
來觸發切換的動作

接著看到2個component各別的內容

CompOne.vue

<template>
    <div>
        <img :src="imgSrc">
        <h2>Component One</h2>
        <p>Choose food.</p>
        <label>
            <input type="radio" name="rbgFood" 
            v-model="imgSrc" :value="'img_apple.svg'" /> 
            Apple
        </label>
        <label>
            <input type="radio" name="rbgFood" 
            v-model="imgSrc" :value="'img_cake.svg'" /> 
            Cake
        </label>
    </div>
</template>

<script>
  export default {
    data () {
      return {
        imgSrc: 'img_question.svg'
      }
    }
  }
</script>

這裡有2個 v-model

<input type="radio" name="rbgFood" v-model="imgSrc" :value="'img_apple.svg'" /> 
<input type="radio" name="rbgFood" v-model="imgSrc" :value="'img_cake.svg'" /> 

代表 當其中一個 <input type="radio">點選時 imgSrc會等於value的內容, 進而連動到` 切換不同的圖片

CompTwo.vue

<template>
    <div>
        <h2>Component Two</h2>
        <input type="text" v-model="msg" placeholder="Write something...">
        <p>Your message:</p>
        <p><strong>{{ this.msg }}</strong></p>
    </div>
</template>

<script>
  export default {
    data () {
      return {
        msg: ''
      }
    }
  }
</script>

這是有一個 v-model 綁定 msg
<input type="text">輸入數值的時候

msg 就會等於 value的數值,同時連動到 {{ this.msg }}

{{ this.msg }} 或是 {{ msg }} 有時要確認一下,
什麼時候要加上 this.

因此,Dynamic Components就像是切換不同Tab的內容一樣

接著來看 Routing的部份
要看安裝 Vue Router 的套件

執行

npm install vue-router@4

來安裝到 node_modules 目錄中

以下是範例程式
main.js

import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'

import App from './App.vue'
import FoodItems from './components/FoodItems.vue'
import AnimalCollection from './components/AnimalCollection.vue'

const router = createRouter({
    history: createWebHistory(),
    routes: [
        { path: '/animals', component: AnimalCollection },
        { path: '/food', component: FoodItems },
    ]
});

const app = createApp(App)

app.use(router);

app.mount('#app')
                  

首先看到 import { createRouter, createWebHistory } from 'vue-router'
vue-router 套件匯入 createRouter, createWebHistory 這2個方法

接著是

import FoodItems from './components/FoodItems.vue'
import AnimalCollection from './components/AnimalCollection.vue'

匯入2個元件 FoodItems,AnimalCollection,其原始檔存在 ./components/ 資料夾中

再來是建立Router的語法

const router = createRouter({
    history: createWebHistory(),
    routes: [
        { path: '/animals', component: AnimalCollection },
        { path: '/food', component: FoodItems },
    ]
});

利用 const router = createRouter({}) 建立

設定path 路徑 /animals 對應到 component AnimalCollection
設定path 路徑 /food 對應到 component FoodItems

最後是 app.use(router);router 加到app

接著是App.vue

<template>
  <p>Choose what part of this page you want to see:</p>
  <router-link to="/animals">Animals</router-link>
  <router-link to="/food">Food</router-link><br>
  <div>
    <router-view></router-view>
  </div>
</template>

其中 <router-link to="/animals">Animals</router-link> 可以看作是 <button>,<a>
的 click 的效果一樣,接下就將網址切換到 to="/animals" 也就是 http://localhost:5173/animals 的路徑上
對應要切換到的內容,會顯示在 <router-view></router-view>

所以整個流程是

import { createRouter, createWebHistory } from 'vue-router' 
import FoodItems from './components/FoodItems.vue'
import AnimalCollection from './components/AnimalCollection.vue'

const router = createRouter({
    history: createWebHistory(),
    routes: [
        { path: '/animals', component: AnimalCollection },
        { path: '/food', component: FoodItems },
    ]
});

<router-link to="/animals">Animals</router-link>
<router-link to="/food">Food</router-link>

<router-view></router-view>

另外 style 的部份,有看到

<style scoped>
a {
    display: inline-block;
    background-color: black;
    border: solid 1px black;
    color: white;
    padding: 5px;
    margin: 10px;
  }
  a:hover,
  a.router-link-active {
    background-color: rgb(110, 79, 13);
  }
</style>

<style scoped> 代表 style 的有效範圍是在 App.vue<template>
還有 有看到 a, a:hover, a.router-link-active 的樣式

代表 <router-link> 在渲染後會變換為 <a>

查看一下,渲染後的結果

<div id="app" data-v-app="">
  <p data-v-05ad211a="">Choose what part of this page you want to see:</p><a data-v-05ad211a="" href="/animals" class="">Animals</a><a data-v-05ad211a="" href="/food" class="router-link-active router-link-exact-active" aria-current="page">Food</a><br data-v-05ad211a="">
  <div data-v-05ad211a=""> 
    <h1 data-v-05ad211a="">Food!</h1>
  </div>
</div>

<router-link to="/animals">Animals</router-link> 轉換為
<a data-v-05ad211a="" href="/animals" class="">Animals</a>

<router-link to="/food">Food</router-link> 轉換為
<a data-v-05ad211a="" href="/food" class="router-link-active router-link-exact-active" aria-current="page">Food</a>

這樣就很清楚知道樣式不是下在 <router-link> 而是 <a>
因此Routing 渲染後的DOM元素對應的樣式名稱有那些,在渲染前就要先設定好
像是 router-link-active,router-link-exact-active

可以參考 Vue Router 的 API Reference
https://v3.router.vuejs.org/api/#router-link

Vue Router 的官網
https://v3.router.vuejs.org/

可以更進一步研究 Vue Router 的用法

Vue Router的概念可以想成是,透過網址的路徑來達到切換不同網頁內容的方法

流程是
當網址為 http://localhost:5173/animals
就會連結到 { path: '/animals', component: AnimalCollection }
./component/AnimalCollection.vue 的內容上

因此,傳統的 http://localhost:5173/animals/index.html?id=12 轉換成 vue router的寫法
大致會變成 http://localhost:5173/animals/12

router 的設定調整成
routes: [ { path: '/animals/:id', component: AnimalCollection }]

利用 {{ $route.params.id }} 來讀取 綁定的:id
AnimalCollection.vue

<template>
    <h1>Animals!</h1>
    <div>id: {{ $route.params.id }}</div>
</template> 
pattern matched path $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: '123' }

最後是根目錄路徑的寫法

import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import './style.css'
import App from './App.vue'
import Home from './views/Home.vue'
import About from './views/About.vue'
 
const routes = [{
    path: "/",
    name: "Home",
    component: Home
  },
  {
    path: "/about/:id",
    name: "About",
    component: About
  }
]

原本的App.vue變成最外層的容器
http://localhost:5173/ 會對應到 Home.vue的內容
http://localhost:5173/about 會對應到 About.vue的內容
http://localhost:5173/about/123 會對應到 About.vue的內容 並將 123 傳入
{{ $route.params.id }} 呈現出來


上一篇
V25_Vue的slot網頁內容的分解及組合
下一篇
V27_Vue的小專案_youtube點播機(1)
系列文
業主說給你30天學會Vue31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言