今天來研究一下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 }}
呈現出來