vue3 快速入門系列 - vue3 路由 在vue3 基礎上加入路由。 vue3 需要使用 vue-router V4,相對於 v3,大部分的 Vue Router API 都沒有變化。 Tip:不瞭解路由的同學可以看一下筆者之前的文章:vue2 路由 參考:vue2 路由官網、vue3 路由官網 ...
vue3 快速入門系列 - vue3 路由
在vue3 基礎上加入路由。
vue3 需要使用 vue-router V4
,相對於 v3,大部分的 Vue Router API 都沒有變化。
Tip:不瞭解路由的同學可以看一下筆者之前的文章:vue2 路由
vue-router V4
在 Vue Router API 從 v3(Vue2)到 v4(Vue3)的重寫過程中,大部分的 Vue Router API 都沒有變化,但是在遷移你的程式時,你可能會遇到一些破壞性的變化 —— 從 Vue2 遷移
vue3 需要使用 vue-router 4.x.x 版本。安裝:
PS hello_vue3> npm i vue-router
changed 37 packages, and audited 69 packages in 3s
8 packages are looking for funding
run `npm fund` for details
1 moderate severity vulnerability
To address all issues, run:
npm audit fix
Run `npm audit` for details.
版本:
"dependencies": {
"vue": "^3.4.15",
"vue-router": "^4.3.0"
},
第一個示例
在vue3項目中加入路由。
步驟如下:
- 創建路由
src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
// new Router 變成 createRouter
const router = createRouter({
// mode: 'history' 配置已經被一個更靈活的 history 配置所取代
// 必填。否則報錯:Uncaught Error: Provide the "history" option when calling "createRouter()"
history: createWebHistory(),
routes
})
export default router
Tip:new Router 變成 createRouter
來創建路由;其中模式
需要通過調用方法創建,必填
。
- 創建兩個組件
<template>
<div>
<h1>About</h1>
// 可以通過設置router-link-active類來為被選中的路由添加樣式
<router-link to="/">to Home</router-link>
</div>
</template>
<template>
<div>
<h1>Home</h1>
<router-link to="/about">to About</router-link>
</div>
</template>
- App.vue 中引入
<router-view>
告訴 Vue Router 在哪裡渲染匹配到的組件。
<template>
<router-view></router-view>
</template>
<script lang="ts" setup name="App">
</script>
- main.ts 通過 use 使用路由
import {createApp} from 'vue'
import App from './App.vue'
// 會自動載入 ./router/index.ts
import router from './router'
createApp(App)
// 將 Vue Router 插件安裝到 Vue 實例中,以便在整個應用程式中使用 Vue Router 的功能
// Vue.use(MyPlugin) - 調用 `MyPlugin.install(Vue)`
.use(router)
.mount('#app')
接著就可以通過瀏覽器體驗:
Home
// 點擊,調整到 about 路由
to About
About
// 點擊,調整到 home 路由
to Home
Tip: 通過 .use(router)
在 vue 開發者工具中就會看到路由tab
。
命名路由
Tip: vue2 路由 -> 命名路由
路徑有時太麻煩,可以使用命名路由
替代。
例如將 About 從路徑改為名稱跳轉。核心代碼如下:
// 定義 name
{ path: '/about', component: About, name: 'guanyu' },
// 跳轉
:to="{name: 'guangyu'}"
Tip:to 目前有2種寫法,感覺字元串方式很痛快,對象還需要寫好多,但是到子路由或傳遞參數,會發現還是對象好用。
// 傳遞字元串 - 理解為目標路由的路徑
to="/"
// 傳遞對象
:to="{path: '/'}"
:to="{name: 'guangyu'}"
嵌套路由
Tip:和 vue2 中路由用法相同,詳情請看:vue2 路由 -> 嵌套路由
新建一個 Article 組件,裡面定義一個 router-view。請看示例:
- Article.vue
<template>
<div>
<h1>Article</h1>
// path 需要將一級路由路徑加上,例如 /article,不能只寫 detail。該 name 也方便。
// query 效果:http://localhost:5173/article/detail?id=1
<router-link :to="{ path: '/article/detail', query: { id: 1 } }">文章 id1 詳情</router-link><br>
<router-link :to="{ path: '/article/detail', query: { id: 2 } }">文章 id2 詳情</router-link><br>
// 註:將對象換成字元串,效果相同
<router-link to="/article/detail?id=3">文章 id3 詳情</router-link><br>
<router-view></router-view>
</div>
</template>
<script lang="ts" setup name="App">
// 可以不引入
// import {RouterView,RouterLink} from 'vue-router'
</script>
Tip:可以不引入 import {RouterView,RouterLink} from 'vue-router'
- Detail.vue
<template>
<div>
<h1>文章id: {{ $route.query.id }}</h1>
</div>
</template>
- 增加路由和子路由。子路由的 path 無需增加
/
const routes = [
{ path: '/home', component: Home,},
{
path: '/article',
component: Article,
children: [
{
path: 'detail',
component: Detail
}
]
},
]
- Home.vue 增加Article入口
<router-link :to="{name: 'guanyu'}">About</router-link>
<br>
<router-link :to="{path: '/article'}">Article</router-link>
測試:進入Home,點擊 Article,點擊 文章 id1 詳情
,顯示 文章id: 1
,測試通過。
路由 query 參數
在”嵌套路由“中我們是這樣取得 query 參數:<h1>文章id: {{ $route.query.id }}</h1>
js 中通過 useRoute
hooks 取得 $route。請看示例:
<template>
<div>
<h1>文章id: {{ $route.query.id }}</h1>
<h1>文章id: {{ query.id }}</h1>
</div>
</template>
<script lang="ts" setup name="App">
import {toRefs} from 'vue'
// 返回當前的路由地址。相當於在模板中使用 $route。
// useRouter 返迴路由器實例。相當於在模板中使用 $router
import {useRoute} from 'vue-router'
const route = useRoute()
// route: Proxy
console.log('route: ', route);
// 錯誤:解構需要用到 toRefs,否則頁面不會更新
// const {query} = route
// 正確:解構
const {query} = toRefs(route)
</script>
Tip:如果需要解構,需使用 toRefs。若想將 query.id 中的 query 去掉,可以使用後面章節的 路由 props 屬性
,代碼將更優雅
路由 params 參數
Tip:請看 vue2 路由 -> $route.params
將上節 query 參數示例改成 params。
- params需要增加
占位符
,比如:id
{
path: '/article',
component: Article,
children: [
{
name: 'xiangxi',
path: 'detail/:id',
component: Detail
}
]
},
- id傳遞方式調整一下,不用 query 那種方式:
<router-link to="/article/detail/4">文章 id4 詳情</router-link><br>
- 接收 id
<h1>文章id: {{ $route.params.id }}</h1>
註
:params 不能傳數組或對象;/a/:b/:c
,則你必須傳 /a/1/2,如果傳 /a/1 則報錯,如果有時沒有c 可傳,可以改成 /a/:b/:c?
對象形式
將 to 改成對象形式:
<router-link :to="{
path: '/article/detail/4',
params: {
id: 5
}
}">文章 id5 詳情</router-link><br>
瀏覽器報錯更容易理解,說 path 被忽略:
// vscode 報錯:
對象字面量只能指定已知屬性,並且“params”不在類型“RouteLocationPathRaw”中。
// 瀏覽器報錯
[Vue Router warn]: Path "/article/detail/4" was passed with params but they will be ignored. Use a named route alongside params instead.
將 path 改成 name即可:
<router-link :to="{
// path: '/article/detail/4',
name: 'xiangxi',
params: {
id: 5
}
}">文章 id5 詳情</router-link><br>
路由 props 屬性
不就是想接收 params 或 query 傳來的參數的,還得寫這麼一大塊代碼,太麻煩:
<template>
<div>
<h1>文章id: {{ query.id }}</h1>
</div>
</template>
<script lang="ts" setup name="App">
import {toRefs} from 'vue'
import {useRoute} from 'vue-router'
const route = useRoute()
const {query} = toRefs(route)
</script>
可以通過 props
解決。細節如下:
props 布爾
- 定義 props
{
name: 'xiangxi',
path: 'detail/:id',
component: Detail,
// 通過 props 屬性來將路由參數傳遞給組件
// 底層好些這樣:<Detail id=5/>
props: true
}
- 直接通過 defineProps 接收
<template>
<div>
<h1>文章id: {{id }}</h1>
</div>
</template>
<script lang="ts" setup name="App">
defineProps(['id'])
</script>
props 函數
如果需要接收 query,需要用 props 函數,參數是 route,返回需要接收的對象:
// RouteLocationNormalized 是 Vue Router 中的一個類型,它用於描述路由的位置信息
import { type RouteLocationNormalized } from 'vue-router';
{
name: 'xiangxi',
path: 'detail',
component: Detail,
// 通過 props 屬性來將路由參數傳遞給組件
// props: true
props(route: RouteLocationNormalized ) {
return route.query
}
}
- 觸發路由從 params 改成 query:
<router-link :to="{
name: 'xiangxi',
query: {
id: 5
}
}">文章 id5 詳情</router-link><br>
- 接收方式不變:
<template>
<div>
<h1>文章id: {{id }}</h1>
</div>
</template>
<script lang="ts" setup name="App">
defineProps(['id'])
</script>
Tip:其實 props: true
就相當於下麵這段代碼:
props(route: RouteLocationNormalized ) {
return route.params
}
props 對象
props 還可以寫成對象,但用得較少:
props: {
id: 100
}
replace
HTML5的歷史API包含了pushState(),replaceState()和popstate事件
路由預設是 push。比如啟動第一個示例
,未點擊 home 或 about 導航時,瀏覽器左上方既不能前進也不能後退
,因為棧中只有當前頁面,指針
沒地方去。在你點擊home和about導航後,就可以前進和後退,即使刷新頁面,這個歷史記錄也不會變。
<router-link :to="{name: 'guanyu'}">About</router-link>
<br>
<router-link :to="{path: '/article'}">Article</router-link>
vue-router 的 replace 作用和用法和 react replace 相同。
現在點 About 就會直接替換
<router-link replace :to="{name: 'guanyu'}">About</router-link>
編程式導航
Tip:vue2 路由 -> 編程式導航
三秒後跳轉到 article:
<script lang="ts" setup name="App">
import { useRouter } from 'vue-router'
const router = useRouter()
type Path = string
// 說vue2 中編程式導航重覆跳轉會報錯,vue3中沒這個問題
function to(path: Path){
router.push(path)
}
setTimeout(() => {
to('/article')
}, 3000)
</script>
編程式導航使用頻率大於聲明式導航(<router-link :to="...">
)
to也支持對象
,和聲明式導航用法相同,更多介紹請看:vuer-router v4 編程式導航
其他
路由組件和一般組件
路由組件
通常放在 pages 或 views 文件夾中,一般組件
通常放在 components 文件夾中 —— 一般開源的項目都會這樣分類
看一個組件是哪種,需要看其如何用。比如定義一個 Demo.vue,如果通過標簽 <Demo/>
這種寫法來使用,就屬於一般組件,如果該組件通過路由渲染,則稱為路由組件。
卸載和掛載
通過導航,視覺上消失的路由組件,預設被卸載,需要用的時候在掛載。
在 第一個示例
中給 About.vue 增加兩個生命周期鉤子,再次切換 Home 和 About 組件,就能看到效果:
<template>
<div>
<h1>About</h1>
<router-link to="/">Home</router-link>
</div>
</template>
<script lang="ts" setup name="App">
import {onMounted, onUnmounted} from 'vue'
onMounted(() => {
console.log('About 掛載了');
})
onUnmounted(() => {
console.log('About 卸載了');
})
</script>
路由模式
history 模式
url 美觀,後期上線,需要服務端配合處理路徑問題,否則刷新會有404。當用戶在瀏覽器中直接訪問一個路由,或者刷新頁面時,如果伺服器端沒有正確配置,可能會導致 404 錯誤,因為此時伺服器會嘗試去尋找對應的文件或路由路徑,而實際上這個路徑是由前端控制的,並不一定存在於伺服器端的文件系統中。為瞭解決這個問題,你需要在伺服器端配置一個通配符路由,將所有的路由請求都指向你的應用的入口文件(比如 index.html),這樣就會確保 Vue Router 能夠正確地處理路由請求。
如果你使用的是 Node.js 伺服器,可以使用 Express 框架來進行配置,示例代碼如下所示:
const express = require('express');
const path = require('path');
const app = express();
// 靜態資源目錄,例如你的 CSS、JavaScript 文件等
app.use(express.static(path.join(__dirname, 'public')));
// 通配符路由,將所有的路由請求都指向 index.html
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
// 啟動伺服器,監聽埠
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
這樣配置後,無論用戶訪問哪個路由,伺服器都會返回 index.html,然後 Vue Router 就可以根據路由配置來正確地渲染相應的組件,避免了刷新頁面時出現的 404 錯誤。
Hash 模式
在 SEO 優化方面相對較差。
- 比如
不利於搜索引擎爬蟲
:Hash 模式下,URL 中的哈希部分(#後面的內容)不會被包含在 HTTP 請求中,因此在伺服器接收請求時,哈希部分對於伺服器來說是不可見的。這意味著搜索引擎爬蟲無法直接獲取到 URL 中的實際內容,因為爬蟲主要是通過 HTTP 請求獲取頁面內容的,所以無法獲取到 hash 後面的內容,這樣就會導致搜索引擎無法正確地索引和解析頁面。
雖然使用 history 模式相對於 hash 模式在 SEO 優化方面有所改善,但它仍然是單頁應用(SPA),可以和服務端渲染結合
沒有匹配到指定的路徑 /
配置如下路由,第一次打開,瀏覽器控制台有警告:main.ts:9 [Vue Router warn]: No match found for location with path "/"
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About, name: 'guanyu' }
]
可以通過重定向解決。就像這樣:
const routes = [
{ path: '/', redirect: '/home'},
{ path: '/home', component: Home,},
出處:https://www.cnblogs.com/pengjiali/p/18123646
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。