六:vue-router (重要)
(一). 對路由的理解
1.什么是路由
路由(Router) 是管理頁面跳轉和 URL 與視圖映射關系的機制,核心作用是:根據不同的 URL 路徑,展示對應的頁面內容,實現單頁應用(SPA)的頁面切換。
一個路由就是一組對應關系(key—value)。
key為路徑,value可能是function或component。
核心概念:
-
URL 與視圖的映射
路由會將 URL 路徑(如/home
、/about
)與對應的組件(頁面)關聯起來,當 URL 變化時,自動渲染匹配的組件,而無需刷新整個頁面(這是 SPA 的核心特性)。 -
單頁應用(SPA)的基礎
傳統多頁應用通過服務器返回不同 HTML 頁面實現跳轉,而路由讓 SPA 能在一個 HTML 頁面內,通過切換組件模擬多頁效果,提升用戶體驗(減少加載時間)。
以下是對圖片內容的提取與整理,清晰區分后端路由和前端路由的核心差異:
2.路由分類
2.1. 后端路由
-
理解:
- 路由的
value
是函數,專門處理客戶端(如瀏覽器)的請求。 - 作用:服務器接收到請求后,通過路徑匹配對應的處理函數,返回數據或頁面。
- 路由的
-
工作過程:
- 客戶端(瀏覽器)發送請求(如
GET /api/users
)。 - 服務器根據請求路徑,找到匹配的函數(如 Node.js 的
app.get('/api/users', (req, res) => { ... })
)。 - 函數處理請求(查數據庫、拼接數據等),返回響應(如 JSON 數據、HTML 頁面)。
- 客戶端(瀏覽器)發送請求(如
2.2. 前端路由
-
理解:
- 路由的
value
是組件(component),用于動態展示頁面內容(SPA 單頁應用的核心)。 - 作用:在瀏覽器端實現頁面切換,無需刷新整個頁面。
- 路由的
-
工作過程:
- 瀏覽器的 URL 路徑變化(如從
/home
到/about
)。 - 前端路由根據路徑變化,匹配對應的組件(如 Vue 中
vue-router
的配置)。 - 匹配的組件渲染到頁面,實現“局部更新”(無需服務器參與)。
- 瀏覽器的 URL 路徑變化(如從
2.3核心差異對比
對比項 | 后端路由 | 前端路由 |
---|---|---|
處理位置 | 服務器端 | 瀏覽器端 |
value 類型 | 函數(處理請求、返回響應) | 組件(展示頁面內容) |
頁面刷新 | 每次請求可能刷新整個頁面 | 僅局部更新,無整頁刷新 |
典型技術 | Node.js(Express)、Java(SpringMVC) | Vue Router、React Router |
2.4總結
- 后端路由:負責“服務器如何響應請求”,用函數處理路徑并返回數據/頁面。
- 前端路由:負責“瀏覽器如何切換內容”,用組件匹配路徑并局部更新頁面。
前端路由是 SPA 應用的基礎,讓頁面跳轉像“切換組件”一樣絲滑~
3.前端路由的實現原理
主要依賴兩種瀏覽器特性:
hash
模式:利用 URL 中的#
后面的部分(如http://xxx.com/#/home
),hash
變化不會觸發頁面刷新,通過onhashchange
事件監聽變化。history
模式:使用 HTML5 的history API
(如pushState
、replaceState
),可以修改 URL 且不發送請求,通過popstate
事件監聽變化。
(二).路由高級
- 嵌套路由(
children
數組,配置子路由規則,對應組件內用<router-view>
顯示 )- 路由守衛:全局守衛(
router.beforeEach
)、組件內守衛(beforeRouteEnter
等 )、路由獨享守衛(beforeEnter
),用于權限校驗、導航控制- 路由懶加載(
component: () => import('./MyRoute.vue')
):優化首屏加載速度
1.嵌套(多級)路由
1.嵌套路由,也叫子路由,是指在一個路由組件中,還可以再嵌套其他的路由組件。在 Vue Router 中,它能夠幫助構建更加復雜且層次分明的單頁應用結構,讓頁面的組織和導航更加清晰。
應用場景
當頁面存在層級關系時,適合使用嵌套路由。比如電商網站中,商品詳情頁是一個大的頁面,在商品詳情頁中,又可以有商品介紹、用戶評價、相關推薦等子頁面,這些子頁面就可以通過嵌套路由來實現。
配置步驟(以 Vue Router 在 Vue 項目中的使用為例)
1. 定義路由配置
在 router/index.js
文件中(假設這是路由配置文件),進行如下配置:
import Vue from 'vue'
import VueRouter from 'vue-router'
import ParentComponent from '../components/ParentComponent.vue'
import ChildComponent1 from '../components/ChildComponent1.vue'
import ChildComponent2 from '../components/ChildComponent2.vue'Vue.use(VueRouter)const routes = [{path: '/parent',component: ParentComponent,children: [{path: 'child1',component: ChildComponent1},{path: 'child2',component: ChildComponent2}]}
]const router = new VueRouter({routes
})export default router
在上述代碼中,定義了一個父路由 '/parent'
,其對應的組件是 ParentComponent
。在 children
數組中,又定義了兩個子路由 'child1'
和 'child2'
,分別對應 ChildComponent1
和 ChildComponent2
。
2. 父組件中設置路由出口
在 ParentComponent.vue
中,需要設置 <router-view>
來顯示子路由對應的組件:
<template><div><h1>這是父組件</h1><router-link to="/parent/child1">子組件1</router-link><router-link to="/parent/child2">子組件2</router-link><router-view></router-view></div>
</template>
這里通過 <router-link>
創建了導航鏈接,點擊鏈接時,會在 <router-view>
中顯示對應的子路由組件。
訪問嵌套路由
當訪問 http://localhost:8080/parent/child1
時,會顯示 ParentComponent
的內容,同時在 <router-view>
中渲染 ChildComponent1
的內容;訪問 http://localhost:8080/parent/child2
時,則渲染 ChildComponent2
的內容。
嵌套路由的注意事項
- 子路由路徑:子路由的路徑不要加
/
開頭,否則會被當作根路徑。 - 嵌套層級:可以根據實際需求進行多層嵌套,但層級過深可能會使代碼復雜度增加,維護起來更困難。
- 路由匹配規則:當訪問父路由時,如果沒有匹配到具體的子路由,
<router-view>
中不會渲染任何內容,有時需要設置一個默認子路由來避免這種情況,比如:
{path: '/parent',component: ParentComponent,children: [{path: '', // 空字符串表示默認子路由component: ChildComponent1},{path: 'child1',component: ChildComponent1},{path: 'child2',component: ChildComponent2}]
}
這樣,當訪問 /parent
時,會默認顯示 ChildComponent1
的內容。
通過嵌套路由,可以讓單頁應用的頁面結構更加清晰合理,提升用戶體驗和代碼的可維護性。
2.路由守衛
在 Vue Router 中,路由守衛是一種非常強大的功能,用于在路由跳轉的不同階段對導航進行攔截和控制,例如進行權限驗證、記錄日志、動態修改路由等。路由守衛主要分為全局守衛、路由獨享守衛和組件內守衛三類。以下是詳細介紹:
2.1全局守衛
全局守衛會對應用中所有的路由跳轉起作用,主要包括以下三種:
router.beforeEach
- 觸發時機:在路由跳轉之前,每次路由切換都會觸發,并且是全局前置守衛,可以對即將發生的導航進行攔截。
- 參數:接收三個參數,分別是
to
(即將要進入的目標路由對象)、from
(當前導航正要離開的路由對象)、next
(一個函數,必須調用它來resolve這個鉤子。執行順序決定了路由是否繼續跳轉 )。 - 示例:
const router = new VueRouter({...})router.beforeEach((to, from, next) => {// 模擬權限驗證,假設用戶登錄后才有權限訪問除登錄頁外的其他頁面const isLoggedIn = localStorage.getItem('token'); if (to.path!== '/login' &&!isLoggedIn) {next('/login'); // 未登錄則重定向到登錄頁} else {next(); // 允許訪問,繼續跳轉}
})
router.beforeResolve
- 觸發時機:在導航被確認之前,在所有組件內守衛和異步路由組件被解析之后,
beforeEach
之后觸發。主要用于確保在導航確認之前,所有異步操作都已經完成。 - 參數:和
beforeEach
一樣,包含to
、from
、next
。 - 示例:
- 觸發時機:在導航被確認之前,在所有組件內守衛和異步路由組件被解析之后,
router.beforeResolve((to, from, next) => {if (to.meta.requiresAsyncData) {// 假設這里有一個異步獲取數據的函數fetchAsyncData(to.params.id).then(() => {next();}).catch(() => {next(false);});} else {next();}
});
router.afterEach
- 觸發時機:在路由跳轉完成之后觸發,沒有
next
函數,不能對導航進行攔截,主要用于進行一些不需要對導航進行干預的操作,比如記錄頁面訪問日志。 - 參數:接收兩個參數,分別是
to
(成功跳轉的目標路由對象)、from
(離開的路由對象)。 - 示例:
- 觸發時機:在路由跳轉完成之后觸發,沒有
router.afterEach((to, from) => {console.log(`從 ${from.path} 跳轉到了 ${to.path}`);// 可以在這里調用接口記錄頁面訪問日志等操作
})
在 Vue Router 中,全局守衛是作用于整個應用所有路由的導航鉤子,用于統一處理路由跳轉的權限驗證、日志記錄、數據預處理等邏輯。全局守衛分為三類,分別在路由跳轉的不同階段觸發,以下是詳細解析:
一、全局前置守衛(beforeEach
)
作用
在路由跳轉前觸發,是全局守衛中最常用的一種,主要用于攔截導航、驗證權限、重定向等操作。
觸發時機
- 每次路由切換(包括初始化時的首次加載)都會觸發。
- 執行順序:在所有組件內守衛和路由獨享守衛之前。
參數
to
:即將進入的目標路由對象(包含路徑、參數、元信息等)。from
:當前正要離開的路由對象。next
:函數,必須調用以決定導航行為:next()
:允許導航繼續。next(false)
:取消導航,停留在當前頁面。next('/path')
或next({ name: 'routeName' })
:重定向到指定路由。next(error)
:傳遞錯誤對象,會被全局錯誤處理器捕獲。
示例(權限驗證)
const router = new VueRouter({... })// 全局前置守衛:驗證用戶是否登錄
router.beforeEach((to, from, next) => {// 1. 登錄頁無需驗證,直接放行if (to.path === '/login') {next();return;}// 2. 非登錄頁:檢查是否有登錄憑證(如 token)const token = localStorage.getItem('token');if (token) {// 已登錄:允許進入目標路由next();} else {// 未登錄:強制重定向到登錄頁next('/login');}
});
二、全局解析守衛(beforeResolve
)
作用
在導航被確認前觸發,用于確保所有異步操作(如組件加載、數據請求)完成后再進入目標路由。
觸發時機
- 在
beforeEach
之后,afterEach
之前。 - 會等待所有組件內守衛和異步路由組件解析完成后才執行。
參數
與 beforeEach
相同(to
、from
、next
)。
示例(預處理數據)
// 全局解析守衛:確保數據加載完成
router.beforeResolve(async (to, from, next) => {// 如果路由需要預加載數據(通過 meta 標記)if (to.meta.needPreload) {try {// 異步加載數據await fetchData(to.params.id);next(); // 數據加載完成,允許導航} catch (error) {next('/error'); // 加載失敗,重定向到錯誤頁}} else {next(); // 無需預加載,直接放行}
});
三、全局后置鉤子(afterEach
)
作用
在路由跳轉完成后觸發,主要用于執行不需要干預導航的操作(如日志記錄、頁面滾動)。
觸發時機
- 導航已完成,目標組件已渲染。
- 無
next
函數,無法攔截或修改導航。
參數
to
:成功進入的目標路由對象。from
:離開的路由對象。
示例(記錄訪問日志)
// 全局后置鉤子:記錄頁面訪問日志
router.afterEach((to, from) => {// 1. 打印跳轉信息console.log(`從 ${from.path} 跳轉到 ${to.path}`);// 2. 調用接口記錄日志(實際項目中使用 axios 等工具)fetch('/api/log', {method: 'POST',body: JSON.stringify({fromPath: from.path,toPath: to.path,time: new Date().toISOString()})});// 3. 頁面滾動到頂部window.scrollTo(0, 0);
});
四、全局守衛的執行順序
- 觸發路由跳轉 →
beforeEach
(全局前置) - 加載異步路由組件(若有)
- 執行目標路由的路由獨享守衛(
beforeEnter
) - 執行目標組件內的
beforeRouteEnter
守衛 - 所有異步操作完成 →
beforeResolve
(全局解析) - 導航確認,組件渲染 →
afterEach
(全局后置)
五、核心使用場景
beforeEach
:權限驗證、登錄攔截、動態路由生成。beforeResolve
:路由跳轉前的異步數據預處理。afterEach
:頁面訪問日志、滾動位置重置、埋點統計。
六、注意事項
- 避免無限循環:在
beforeEach
中重定向時,需確保條件判斷正確(如登錄頁不重定向自身)。 - 異步操作處理:若有異步邏輯(如接口請求),需用
async/await
包裹,并在完成后調用next()
。 - 性能影響:全局守衛會攔截所有路由跳轉,復雜邏輯可能影響性能,建議保持簡潔。
全局守衛是 Vue Router 中實現統一導航控制的核心工具,通過合理組合三類守衛,可實現從權限驗證到數據處理的全流程管控。
2.2路由獨享守衛
可以為某個特定的路由配置守衛,只對該路由生效。
beforeEnter
- 觸發時機:在進入對應的路由之前觸發。
- 參數:接收三個參數,分別是
to
(即將要進入的目標路由對象)、from
(當前導航正要離開的路由對象)、next
(和全局守衛中的next
函數作用相同)。 - 示例:
const router = new VueRouter({routes: [{path: '/admin',component: Admin,beforeEnter: (to, from, next) => {// 只有管理員角色才能訪問const userRole = localStorage.getItem('role'); if (userRole === 'admin') {next();} else {next('/forbidden'); // 無權限則重定向到禁止訪問頁面}}}]
})
在 Vue Router 中,路由獨享守衛是一種僅作用于特定路由配置的導航鉤子,允許你在某個路由跳轉前進行定制化攔截和處理,而不必影響其他路由。以下是其核心用法與場景:
一、核心語法(beforeEnter
)
const router = new VueRouter({routes: [{path: '/admin',component: AdminPanel,beforeEnter: (to, from, next) => {// 路由獨享守衛邏輯if (!isAdmin) {next('/login'); // 無權限則重定向} else {next(); // 允許訪問}}}]
});
二、參數與執行流程
1. 參數
to
:目標路由對象(包含路徑、參數、元信息等)。from
:當前路由對象。next
:控制導航行為的函數(同全局守衛的next
)。
2. 執行時機
- 在全局前置守衛(
beforeEach
)之后,組件內守衛(beforeRouteEnter
)之前執行。 - 僅在進入該路由時觸發,離開時不觸發。
三、典型應用場景
1. 權限控制(如管理員頁面)
{path: '/admin',component: AdminPanel,beforeEnter: (to, from, next) => {const userRole = localStorage.getItem('role');if (userRole === 'admin') {next(); // 管理員允許訪問} else {next('/forbidden'); // 非管理員跳轉至禁止頁}}
}
2. 數據預處理
{path: '/profile/:id',component: UserProfile,beforeEnter: async (to, from, next) => {try {// 預加載用戶數據const user = await fetchUser(to.params.id);// 將數據存入路由元信息,供組件使用to.meta.user = user;next();} catch (error) {next('/404'); // 加載失敗跳轉 404}}
}
3. 導航條件判斷
{path: '/payment',component: PaymentPage,beforeEnter: (to, from, next) => {// 檢查購物車是否有商品const hasItems = localStorage.getItem('cartItems');if (hasItems) {next();} else {next('/cart'); // 無商品則跳轉購物車}}
}
四、與其他守衛的對比
守衛類型 | 作用范圍 | 觸發時機 | 適用場景 |
---|---|---|---|
全局前置守衛 | 所有路由 | 路由跳轉前 | 統一權限驗證、登錄攔截 |
路由獨享守衛 | 單個路由配置 | 進入特定路由前 | 特定頁面的權限控制、數據預加載 |
組件內守衛 | 組件內部 | 組件實例相關的導航階段 | 組件級別的導航邏輯 |
五、注意事項
-
只作用于直接匹配的路由
如果路由配置了子路由,beforeEnter
僅在進入該路由時觸發,不會作用于子路由。 -
避免重復邏輯
若多個路由需要相同的守衛邏輯,建議使用全局守衛或高階函數封裝,減少代碼冗余。 -
異步操作處理
若守衛中包含異步請求(如驗證 Token),需使用async/await
確保數據加載完成后再調用next()
。
六、總結
路由獨享守衛是 Vue Router 中實現細粒度導航控制的靈活工具,適合在不影響全局導航的前提下,對特定路由添加定制化的攔截邏輯。合理使用它可提升代碼的可維護性,避免全局守衛過于臃腫。
2.3組件內守衛
在路由組件內部定義的守衛,只在當前組件對應的路由跳轉時生效。
beforeRouteEnter
- 觸發時機:在路由進入該組件之前觸發,此時組件實例還未被創建,所以不能訪問
this
。 - 參數:接收三個參數,分別是
to
(即將要進入的目標路由對象)、from
(當前導航正要離開的路由對象)、next
(next
函數可以接收一個回調函數,在組件實例創建好之后執行 )。 - 示例:
- 觸發時機:在路由進入該組件之前觸發,此時組件實例還未被創建,所以不能訪問
export default {beforeRouteEnter(to, from, next) {// 模擬獲取數據后再進入組件getData().then(data => {next(vm => {vm.$data.data = data; // vm 是組件實例});}).catch(() => {next(false);});}
}
beforeRouteUpdate
- 觸發時機:在當前路由改變,但是該組件被復用時調用,比如在帶有動態參數的路由中,當參數變化時,組件會被復用,此時會觸發該守衛。
- 參數:接收三個參數,分別是
to
(即將要進入的目標路由對象)、from
(當前導航正要離開的路由對象)、next
(和其他守衛中的next
函數作用相同)。 - 示例:
export default {beforeRouteUpdate(to, from, next) {// 當路由參數變化時,重新獲取數據if (to.params.id!== from.params.id) {this.fetchNewData(to.params.id);}next();}
}
beforeRouteLeave
- 觸發時機:在導航離開該組件時觸發,可用于詢問用戶是否確認離開,比如用戶在表單中輸入了內容還未保存時。
- 參數:接收三個參數,分別是
to
(即將要進入的目標路由對象)、from
(當前導航正要離開的路由對象)、next
(和其他守衛中的next
函數作用相同)。 - 示例:
export default {beforeRouteLeave(to, from, next) {if (this.hasUnsavedChanges) {const confirmLeave = window.confirm('你有未保存的更改,確定要離開嗎?');if (confirmLeave) {next();} else {next(false);}} else {next();}}
}
通過合理運用這些路由守衛,可以實現豐富且強大的導航控制邏輯,提升應用的安全性和用戶體驗。
在 Vue Router 中,組件內守衛是直接定義在路由組件內部的導航鉤子,用于控制該組件實例相關的路由導航行為。與全局守衛和路由獨享守衛不同,組件內守衛僅作用于當前組件,提供更精細的導航控制。以下是其核心用法與場景:
一、三種組件內守衛
1. beforeRouteEnter
- 觸發時機:在路由進入組件前觸發,此時組件實例尚未創建,因此無法訪問
this
。 - 用途:可通過
next
回調訪問組件實例,常用于在路由進入前預加載數據。 - 示例:
export default {beforeRouteEnter(to, from, next) {// 異步獲取數據(如用戶信息)fetchUser(to.params.id).then(user => {// 通過 next 回調訪問組件實例next(vm => {vm.user = user; // 將數據傳遞給組件實例});});} }
2. beforeRouteUpdate
- 觸發時機:在當前路由改變(如參數變化)但組件被復用時觸發,此時組件實例已存在,可訪問
this
。 - 用途:常用于動態參數路由(如
/user/:id
)的更新邏輯,避免組件重復創建。 - 示例:
export default {watch: {// 傳統方式:監聽 $route 變化$route(to) {this.fetchData(to.params.id);}},// 更優解:使用組件內守衛beforeRouteUpdate(to, from, next) {// 參數變化時重新加載數據if (to.params.id !== from.params.id) {this.fetchData(to.params.id);}next();} }
3. beforeRouteLeave
- 觸發時機:在導航離開當前組件時觸發,可訪問
this
。 - 用途:常用于阻止用戶意外離開(如未保存表單),或清理資源。
- 示例:
export default {data() {return {formDirty: false // 表單是否已修改};},beforeRouteLeave(to, from, next) {if (this.formDirty) {const confirmLeave = window.confirm('表單尚未保存,確定離開?');confirmLeave ? next() : next(false); // 確認后允許離開} else {next(); // 未修改直接放行}} }
二、組件內守衛的執行順序
當路由發生變化時,守衛的觸發順序為:
- 全局:
beforeEach
- 路由獨享:
beforeEnter
- 組件內:
- 當前組件的
beforeRouteLeave
(若離開當前組件) - 目標組件的
beforeRouteEnter
(若進入新組件)
- 當前組件的
- 全局:
beforeResolve
- 全局:
afterEach
三、典型應用場景
1. 數據預加載
export default {beforeRouteEnter(to, from, next) {// 進入組件前預加載文章數據fetchArticle(to.params.id).then(article => {next(vm => {vm.article = article;});});}
}
2. 動態路由參數更新
export default {beforeRouteUpdate(to, from, next) {// 當路由參數變化時(如從 /user/1 到 /user/2)this.fetchUser(to.params.id);next();}
}
3. 防止數據丟失
export default {beforeRouteLeave(to, from, next) {// 檢查是否有未保存的草稿if (this.hasDraft) {saveDraft().then(() => next());} else {next();}}
}
四、與其他守衛的對比
守衛類型 | 定義位置 | 能否訪問 this | 適用場景 |
---|---|---|---|
全局守衛 | 路由配置文件 | 否 | 全局權限驗證、日志記錄 |
路由獨享守衛 | 路由配置對象 | 否 | 特定路由的權限控制 |
組件內守衛 | 組件內部 | beforeRouteEnter 不可,其他可 | 組件級的導航邏輯、數據預加載 |
五、注意事項
-
beforeRouteEnter
中訪問組件實例
由于此時組件尚未創建,需通過next(vm => { ... })
回調訪問實例。 -
避免重復邏輯
若多個組件需要相同的守衛邏輯,可使用 mixin 或全局守衛減少代碼冗余。 -
異步操作處理
若守衛中包含異步請求(如驗證 Token),需確保數據加載完成后再調用next()
。
六、總結
組件內守衛是 Vue Router 中實現組件級導航控制的強大工具,通過 beforeRouteEnter
、beforeRouteUpdate
和 beforeRouteLeave
三個鉤子,可精確控制組件實例的導航生命周期。合理使用組件內守衛能提升用戶體驗(如防止數據丟失),并優化組件性能(如復用組件時的數據更新)。
3.history模式與hash模式
在 Vue Router 中,history
模式和**hash
模式**是兩種不同的路由實現方式,主要區別在于 URL 的表現形式和瀏覽器歷史記錄的處理方式。以下是詳細對比與選擇建議:
一、核心區別
特性 | hash 模式(默認) | history 模式 |
---|---|---|
URL 格式 | http://example.com/#/home | http://example.com/home |
路徑標識符 | 使用 # 符號分隔路徑(如 #/user/1 ) | 直接使用真實路徑(如 /user/1 ) |
歷史記錄 | hash 變化會觸發瀏覽器歷史記錄,但不會向服務器發送請求 | 依賴 HTML5 History API(pushState /replaceState ),路徑變化會被記錄到歷史中 |
服務器配置 | 無需特殊配置,所有請求都指向根頁面 | 需要服務器配置,確保所有路由請求都返回同一個 HTML 文件 |
兼容性 | 支持所有瀏覽器(包括 IE9+) | 依賴 HTML5 History API,IE9 及以下不支持 |
二、hash 模式詳解
- 工作原理
- URL 中的
#
及其后的內容被視為瀏覽器的hash
值,不會被發送到服務器。 - 當
hash
變化時(如#/home
→#/about
),Vue Router 會攔截并根據hash
值渲染對應組件。
- 優點
- 無需服務器配置:所有請求都指向根頁面(如
index.html
),適合快速開發和靜態網站。 - 兼容性強:支持所有現代瀏覽器,甚至包括 IE9。
- 缺點
- URL 不美觀:
#
符號在 URL 中較為突兀,不符合傳統 URL 格式。 - SEO 不友好:搜索引擎爬蟲通常會忽略
hash
值,不利于頁面收錄。
三、history 模式詳解
- 工作原理
- 使用 HTML5 的
pushState
和replaceState
API 操作瀏覽器歷史記錄,URL 看起來像傳統的靜態頁面路徑(如/home
)。 - 當用戶訪問
/user/1
時,瀏覽器會向服務器發送請求,但實際上所有路徑都應返回同一個 HTML 文件(如index.html
),由 Vue Router 在客戶端處理路由邏輯。
- 優點
- URL 更優雅:沒有
#
符號,符合傳統 URL 格式,提升用戶體驗。 - SEO 友好:搜索引擎可以直接抓取真實路徑,有利于頁面收錄。
- 缺點
- 服務器配置復雜:需要服務器配置所有路由請求都返回
index.html
,否則會出現 404 錯誤(見下方服務器配置示例)。 - 兼容性較差:不支持 IE9 及以下瀏覽器。
四、服務器配置示例(history 模式)
- Node.js (Express)
const express = require('express');
const app = express();// 靜態文件處理
app.use(express.static(__dirname + '/dist'));// 所有路由請求都返回 index.html
app.get('*', function(req, res) {res.sendFile(__dirname + '/dist/index.html');
});app.listen(8080);
五、如何選擇?
-
優先使用 history 模式:
如果項目需要良好的 SEO、更優雅的 URL,且不考慮 IE9 及以下瀏覽器,推薦使用 history 模式。 -
使用 hash 模式的場景:
- 項目不需要 SEO(如內部管理系統)。
- 無法配置服務器(如 GitHub Pages、靜態網站托管)。
- 需要兼容 IE9 及以下瀏覽器。
六、切換模式的方法
在 Vue Router 配置中,通過 mode
選項指定模式:
const router = new VueRouter({mode: 'history', // 啟用 history 模式(默認是 hash 模式)routes: [...]
});
七、總結
場景 | hash 模式 | history 模式 |
---|---|---|
靜態網站/快速開發 | ? | ?(需服務器配置) |
企業內部系統 | ?(兼容性好) | ?(URL 更優雅) |
電商/內容網站(需 SEO) | ? | ? |
兼容性要求 | ?(支持 IE9+) | ?(不支持 IE9 及以下) |
選擇時需權衡 URL 美觀性、SEO 需求、服務器配置復雜度和瀏覽器兼容性。history 模式是現代 Web 應用的首選,但需要服務器配合;hash 模式則適用于快速迭代和兼容性要求高的場景。
(三)、vue-router(路由管理)
vue的一個插件庫,專門用來實現SPA應用
1.安裝與配置
使用npm install vue-router@3
安裝,然后在項目中進行配置。
使用:Vue.use(Router);
// router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';Vue.use(Router);export default new Router({// 路由模式,可選'hash'(默認,URL中包含#)和'history'(更美觀的URL)mode: 'history', routes: [{// 路由路徑path: '/', // 路由名稱name: 'Home', // 對應的組件component: Home },{path: '/about',name: 'About',component: About}]
});
在main.js
中引入并使用路由:
import Vue from 'vue';
import App from './App.vue';
import router from './router';new Vue({router,render: h => h(App)
}).$mount('#app');
2.路由導航與參數
- 導航:使用
<router-link>
組件進行路由導航。
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
- 動態路由參數:在路由路徑中使用參數,如
/user/:id
,可以在組件中通過$route.params
獲取參數值。
// User.vue
export default {created() {const userId = this.$route.params.id;console.log('用戶ID:', userId);}
};
(四)對SPA應用的理解
- 定義:單頁 Web 應用(single page web application,SPA )
- 頁面特征:整個應用只有一個完整的頁面
- 交互特點:點擊頁面中的導航鏈接不會刷新頁面,只會做頁面的局部更新
- 數據獲取:數據需要通過 ajax 請求獲取
(五)基本路由
注意:
- 存儲位置
- 路由組件:通常存放在
pages
文件夾 - 一般組件:通常存放在
components
文件夾
- 路由組件:通常存放在
- 路由組件銷毀與掛載:通過切換,“隱藏”了的路由組件,默認是被銷毀掉的,需要的時候再去掛載
- 組件路由信息屬性:每個組件都有自己的
$route
屬性,里面存儲著自己的路由信息 - 全局路由實例獲取:整個應用只有一個
router
,可以通過組件的$router
屬性獲取到 。
路由傳參
query參數(靜態)
命名路由
一、命名路由的作用
簡化路由跳轉:無需硬編碼完整路徑,通過路由名稱(name
)實現跳轉,避免路徑變更時大量修改代碼。
二、使用步驟
1. 給路由“命名”(配置階段)
在路由配置中,為目標路由添加 name
屬性:
const routes = [{path: '/demo',component: Demo,children: [{path: 'test',component: Test,children: [{name: 'hello', // 給路由命名(關鍵)path: 'welcome',component: Hello}]}]}
]
2. 簡化跳轉(組件中使用)
未簡化前:需寫完整路徑,易出錯且難維護:
<router-link to="/demo/test/welcome">跳轉</router-link>
簡化后:通過 name
跳轉,路徑變化時只需改配置:
<router-link :to="{ name: 'hello' }">跳轉</router-link>
簡化寫法:命名路由 + query 參數
<!-- 簡化寫法:命名路由 + query 參數 -->
<router-link :to="{ name: 'hello', // 路由名稱(對應路由配置的 name: 'hello')query: { // 傳遞 query 參數(會顯示在 URL 中,如 ?id=666&title=你好)id: 666, title: '你好' } }"
>跳轉并傳參
</router-link>
三、核心優勢
- 解耦路徑與跳轉:路由名稱不變時,即使路徑(如
/demo/test/welcome
)修改,跳轉代碼無需改動。 - 支持動態參數:結合
params
/query
傳參更靈活(如:to="{ name: 'hello', params: { id: 1 } }"
)。
總結
命名路由是給路由起一個“別名”(name
),讓跳轉從“寫死路徑”變成“調用名稱”,核心價值是簡化跳轉邏輯、提升可維護性。
路由的params參數(動態)
1.配置路由,聲明接收 params
參數
配置路由以接收
params
參數,通過 占位符(:id
、:title
) 定義動態路徑,讓組件能接收 URL
中的動態參數。
1.1. 路由配置(核心片段)
{path: '/home',component: Home,children: [{component: Message,children: [{name: 'xiangqing', path: 'detail/:id/:title', // 占位符聲明 params 參數component: Detail}]}]
}
代碼解析:
path: 'detail/:id/:title'
:- 用
:id
、:title
占位符,聲明該路由需要接收id
和title
兩個params
參數。 - 訪問時路徑如
/home/message/detail/1/xxx
,其中1
和xxx
會作為params
傳遞。
- 用
流程說明 :
-
路由定義:
通過path: 'detail/:id/:title'
告訴 Vue Router:- 該路徑是動態的,
id
和title
是可變參數。 - 這些參數會以
params
形式傳遞給Detail
組件。
- 該路徑是動態的,
-
參數傳遞與接收:
- 跳轉時需通過
params
傳入數據(如this.$router.push({ name: 'xiangqing', params: { id: 1, title: 'xxx' } })
)。 Detail
組件中通過this.$route.params.id
、this.$route.params.title
接收參數。
- 跳轉時需通過
核心特點
- 動態路徑:URL 中的
id
和title
是動態的,不同參數對應不同頁面狀態。 - 強關聯路由:
params
參數必須與路由配置的占位符一一對應,否則路由無法匹配。
1.2對比 query
參數
對比項 | params 參數 | query 參數 |
---|---|---|
路徑形式 | /detail/1/xxx (參數嵌入路徑) | /detail?id=1&title=xxx (參數跟在 ? 后) |
路由配置 | 需用 :占位符 聲明 | 無需特殊配置 |
參數是否必填 | 是(否則路由不匹配) | 否(可傳可不傳) |
1.3 注意事項
-
參數必填性:
由于params
參數通過占位符聲明,跳轉時必須傳入對應參數,否則路由無法匹配(如少傳title
會導致 404)。 -
命名路由配合:
建議結合name: 'xiangqing'
使用,跳轉時代碼更簡潔:this.$router.push({ name: 'xiangqing', params: { id: 1, title: 'xxx' } })
-
組件接收參數:
在Detail
組件中,通過this.$route.params
而非props
接收(除非開啟props: true
配置)。
這是 Vue Router 中 動態路由傳參 的基礎用法,核心是通過 占位符 讓 URL 攜帶動態數據,常用于商品詳情、文章詳情等場景~
2.params
參數的傳遞方式:
1. 字符串寫法(直接拼接路徑)
<!-- 跳轉并攜帶 params 參數(字符串拼接路徑) -->
<router-link to="/home/message/detail/666/你好">跳轉</router-link>
- 特點:
- 直接拼接
params
到 URL(666
是id
,你好
是title
)。 - 需嚴格按照路由配置的
path: 'detail/:id/:title'
格式拼接,易出錯。
- 直接拼接
2. 對象寫法(推薦)
<!-- 跳轉并攜帶 params 參數(對象寫法) -->
<router-link :to="{ name: 'xiangqing', params: { id: 666, title: '你好' } }"
>跳轉
</router-link>
- 關鍵規則:
- 必須用
name: 'xiangqing'
(路由的命名),不能用path
。 - 通過
params
字段傳遞參數,Vue Router 會自動拼接成動態路徑。
- 必須用
注意事項
對象寫法的強制規則:
- 當用對象傳遞
params
時,必須通過name
匹配路由,而不能用path
。 - 原因:
path
是靜態的,無法動態拼接params
;name
與路由配置的name: 'xiangqing'
關聯,能正確解析params
。
兩種寫法對比
寫法 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
字符串寫法 | 簡單直觀 | 易因路徑變化(如參數順序)出錯 | 簡單場景,參數少且固定 |
對象寫法 | 解耦路徑與參數,更健壯 | 需定義路由 name | 復雜場景,參數多或動態變化 |
核心結論
傳遞 params
參數時:
- 若用 對象寫法,必須配合
name
(不能用path
),這是 Vue Router 的強制規則。 - 推薦優先用 對象寫法,避免路徑拼接錯誤,且更易維護(路由名稱不變時,路徑變化不影響跳轉)。
這是 Vue Router 中 params
參數傳遞的核心細節,記住 “對象寫法必須用 name” 即可避免常見錯誤~
3. 接收 params
參數:
在組件中獲取路由傳遞的 params
參數(如 id
和 title
),用于渲染動態內容(如商品詳情、文章標題)。
1.關鍵代碼
// 組件中接收 params 參數
const id = this.$route.params.id
const title = this.$route.params.title
2.流程說明
-
路由傳遞
params
:
通過router-link
或this.$router.push
傳遞params
(如{ params: { id: 666, title: '你好' } }
)。 -
組件接收參數:
Vue Router 會將params
掛載到this.$route.params
中,組件直接訪問this.$route.params.id
、this.$route.params.title
即可。
3.與 query
參數的區別
參數類型 | 存儲位置 | 組件中獲取方式 | 特點 |
---|---|---|---|
params | 動態路徑(如 /detail/666/你好 ) | this.$route.params.xxx | 參數隱藏在路徑中,更“干凈” |
query | URL 查詢字符串(如 ?id=666 ) | this.$route.query.xxx | 參數顯示在 URL 中,可分享 |
4.注意事項
-
路由配置依賴:
必須在路由中通過path: 'detail/:id/:title'
聲明params
占位符,否則this.$route.params
無法獲取參數。 -
組件更新問題:
如果組件復用(如不同id
但同一路由),需通過watch
監聽$route.params
變化:watch: {'$route.params'() {// 參數變化時重新加載數據this.fetchData(this.$route.params.id);} }
5.總結
接收 params
參數的核心是通過 this.$route.params.xxx
,需注意路由配置的占位符聲明,以及組件復用場景下的參數監聽。這是 Vue Router 動態路由傳參的基礎用法,常用于商品詳情、文章詳情等場景。
路由的props配置
在 Vue Router 中,props
配置是一種將路由參數(如 params
、query
)直接映射為組件 props
的機制,目的是解耦組件與路由,讓組件更易于測試和復用。以下是其核心用法與場景:
一、基礎用法(三種模式)
1. 布爾模式(最常用)
- 配置:
props: true
- 效果:將
params
參數轉為組件props
,query
不處理。 - 示例:
// 路由配置 {path: '/user/:id',component: User,props: true // 開啟 props 模式 }// User 組件 export default {props: ['id'], // 直接接收路由 params 參數mounted() {console.log(this.id); // 訪問路由參數} }
2. 對象模式
- 配置:
props: { key: value }
- 效果:傳遞固定的靜態數據給組件,不依賴路由參數。
- 示例:
{path: '/about',component: About,props: { title: '關于我們', version: '1.0.0' } // 傳遞靜態數據 }
3. 函數模式(最靈活)
- 配置:
props: (route) => ({...})
- 效果:通過函數動態生成
props
,可處理params
、query
或其他邏輯。 - 示例:
{path: '/search',component: Search,props: (route) => ({keyword: route.query.q, // 從 query 獲取參數page: parseInt(route.query.page) || 1 // 處理默認值}) }
匯總:
{name:'xiangqing',path:'detail/:id',component:Detail,//第一種寫法:props值為對象,該對象中所有的key - value的組合最終都會通過props傳給Detail組件// props:{a:900}//第二種寫法:props值為布爾值,布爾值為true,則把路由收到的所有params參數通過props傳給Detail組件// props:true//第三種寫法:props值為函數,該函數返回的對象中每一組key - value都會通過props傳給Detail組件props(route){return {id:route.query.id,title:route.query.title}
二、核心優勢
-
組件復用性提升:
組件不再依賴this.$route
,可獨立使用(如在非路由場景下復用)。// 無 props 配置時,組件依賴路由 console.log(this.$route.params.id); // 耦合路由// 有 props 配置時,組件只關心 props console.log(this.id); // 解耦路由,可獨立測試
-
測試更簡單:
測試組件時,可直接傳入props
,無需模擬路由環境。// 測試代碼示例 const wrapper = shallowMount(User, {propsData: { id: '123' } // 直接傳入 props });
-
代碼更清晰:
組件props
聲明明確,一眼看出依賴哪些參數。
三、對比直接訪問 $route
方式 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
直接用 $route | 簡單直接,無需額外配置 | 組件與路由強耦合 | 小型項目、快速開發 |
props 配置 | 解耦路由,組件可復用 | 需要額外配置 | 中大型項目、組件復用多 |
四、注意事項
-
僅處理
params
:
當props: true
時,只有params
參數會被轉為props
,query
參數需通過函數模式手動處理。 -
與命名路由配合:
傳遞params
時,建議用命名路由(如name: 'user'
),避免路徑拼接錯誤。<router-link :to="{ name: 'user', params: { id: 1 } }">用戶詳情</router-link>
-
函數模式的性能:
函數模式每次路由變化都會執行,避免在函數中做復雜計算,可通過computed
緩存結果。
五、典型場景
-
商品詳情頁:通過
id
獲取商品數據。{path: '/product/:id',component: ProductDetail,props: true }
-
搜索結果頁:通過
query
參數獲取搜索關鍵詞。{path: '/search',component: SearchResult,props: (route) => ({ keyword: route.query.q }) }
-
靜態頁面:傳遞固定數據(如標題、配置)。
{path: '/help',component: HelpPage,props: { title: '幫助中心' } }
總結
props
配置是 Vue Router 中解耦組件與路由的關鍵機制,通過三種模式(布爾、對象、函數)將路由參數轉為組件 props
,讓組件更獨立、可測試、易復用。建議在中大型項目中優先使用,提升代碼質量。
router-link的replace屬性
在 Vue Router 中,router-link
是用于生成導航鏈接的組件,它的 replace
屬性主要用于控制導航行為,以下是關于它的詳細介紹:
以下是提取的文字內容:
<router-link>
的replace
屬性
- 作用:控制路由跳轉時操作瀏覽器歷史記錄的模式
- 瀏覽器的歷史記錄有兩種寫入方式:分別為
push
和replace
,push
是追加歷史記錄,replace
是替換當前記錄。路由跳轉時候默認為push
- 如何開啟
replace
模式:<router-link replace ……>News</router-link>
1. 基本作用
replace
屬性的作用是用新的歷史記錄條目替換當前的歷史記錄條目,而不是向歷史記錄棧中添加一個新條目。
在普通情況下,當我們使用 <router-link>
進行頁面跳轉時,每次跳轉都會在瀏覽器的歷史記錄中新增一條記錄,用戶可以通過點擊瀏覽器的“后退”按鈕回到上一個頁面。但是當給 <router-link>
添加了 replace
屬性后,跳轉時會替換當前的歷史記錄,此時瀏覽器的“后退”按鈕將無法退回到跳轉前的頁面 。
2. 使用方式
在 <router-link>
組件中,直接添加 replace
屬性即可,它不需要綁定具體的值,類似于 HTML 中的布爾屬性,只要存在該屬性,就會生效。示例代碼如下:
<template><div><!-- 普通的路由鏈接,會增加歷史記錄 --><router-link to="/home">前往首頁</router-link> <!-- 使用了replace屬性的路由鏈接,會替換歷史記錄 --><router-link to="/about" replace>前往關于頁面</router-link> </div>
</template>
上述代碼中,點擊“前往首頁”的鏈接時,瀏覽器歷史記錄會新增一條記錄;而點擊“前往關于頁面”的鏈接時,當前的歷史記錄會被替換。
3. 應用場景
- 防止用戶返回:在一些場景下,比如用戶進行了不可逆的操作(如提交表單、支付成功后),不希望用戶通過點擊“后退”按鈕回到之前的頁面,此時可以使用
replace
屬性。例如,在電商網站中,當用戶完成支付后跳轉到支付成功頁面,為了避免用戶誤點“后退”按鈕回到支付頁面造成混亂,可以在支付成功頁面的跳轉鏈接中添加replace
屬性。
<router-link to="/payment-success" replace>支付成功</router-link>
- 簡化歷史記錄:當頁面的導航邏輯比較復雜,且某些跳轉不需要用戶回溯時,使用
replace
屬性可以讓瀏覽器的歷史記錄更加簡潔明了,避免歷史記錄中出現過多不必要的條目 。
4. 與編程式導航的對比
除了通過 <router-link>
的 replace
屬性控制導航行為外,編程式導航(this.$router.push
和 this.$router.replace
)也能實現類似功能。
this.$router.push
:向歷史記錄棧中添加一個新條目,與普通的<router-link>
效果類似。this.$router.replace
:用新的條目替換當前歷史記錄條目,類似于<router-link>
加上replace
屬性。
示例代碼:
export default {methods: {goToPage() {// 普通push,增加歷史記錄this.$router.push('/some-page'); // 使用replace,替換歷史記錄this.$router.replace('/another-page'); }}
}
總之,router-link
的 replace
屬性為我們在 Vue Router 中控制導航的歷史記錄行為提供了一種便捷的方式,合理使用它可以優化用戶體驗和頁面導航邏輯。
編程式路由導航
在 Vue Router 中,除了使用 <router-link>
聲明式創建導航鏈接外,還可以通過 編程式路由導航 實現更靈活的路由跳轉。這種方式通過 JavaScript 代碼觸發路由變化,適用于條件跳轉、事件回調等場景。
一、核心 API
1. this.$router.push(location)
- 作用:向歷史記錄棧中添加一個新條目,等同于
<router-link to>
。 - 參數:可以是字符串路徑或描述目標位置的對象。
- 示例:
// 字符串路徑 this.$router.push('/home');// 對象路徑(命名路由 + params) this.$router.push({ name: 'user', params: { id: 123 } });// 對象路徑(帶 query 參數) this.$router.push({ path: '/search', query: { keyword: 'vue' } });
2. this.$router.replace(location)
- 作用:替換當前歷史記錄條目,不創建新條目,等同于
<router-link replace>
。 - 示例:
// 替換當前路由,禁止返回上一頁 this.$router.replace('/login');
3. this.$router.go(n)
- 作用:在歷史記錄中前進或后退,參數
n
為步數。 - 示例:
this.$router.go(1); // 前進一頁(等同于 history.forward()) this.$router.go(-1); // 后退一頁(等同于 history.back()) this.$router.go(3); // 前進三頁
二、與 <router-link>
的對比
方式 | 適用場景 | 特點 |
---|---|---|
<router-link> | 靜態導航鏈接(如導航欄、菜單) | 聲明式,簡單直觀 |
編程式路由導航 | 動態邏輯跳轉(如按鈕點擊、條件判斷) | 靈活,可結合業務邏輯,支持異步操作 |
三、典型場景
1. 按鈕點擊跳轉
<template><button @click="handleLogin">登錄</button>
</template><script>
export default {methods: {handleLogin() {// 登錄邏輯...this.$router.push('/dashboard');}}
}
</script>
2. 條件跳轉
// 根據用戶權限跳轉
if (this.isAdmin) {this.$router.push('/admin');
} else {this.$router.push('/user');
}
3. 異步操作后跳轉
async fetchData() {await this.api.getUser();this.$router.replace('/profile'); // 替換路由,禁止返回
}
4. 帶參數跳轉
// 傳遞 params 參數
this.$router.push({ name: 'product', params: { id: this.selectedId }
});// 傳遞 query 參數
this.$router.push({ path: '/search', query: { page: 2 }
});
四、注意事項
-
路由鉤子與導航守衛:
編程式導航同樣會觸發全局導航守衛(如beforeEach
)和路由獨享守衛(如beforeEnter
),需注意邏輯順序。 -
命名路由優先:
傳遞動態參數(如params
)時,建議使用命名路由,避免路徑拼接錯誤。 -
錯誤處理:
導航失敗(如路由不存在)會返回一個被拒絕的 Promise,可以通過.catch
捕獲錯誤:this.$router.push('/non-existent').catch(err => {console.error('導航失敗:', err); });
五、總結
編程式路由導航是 Vue Router 提供的 JavaScript 方式控制路由跳轉 的能力,通過 push
、replace
、go
等方法實現靈活的導航邏輯,適用于需要動態控制路由的場景。與 <router-link>
結合使用,能滿足各種復雜的路由需求。
緩存路由組件
在 Vue Router 中,緩存路由組件 是提升單頁應用性能和用戶體驗的重要手段,主要通過 <keep-alive>
組件實現。以下是核心機制與使用場景:
一、核心原理
- 普通組件行為:組件在切換時會被銷毀(
beforeDestroy
/destroyed
),再次進入時重新創建(created
/mounted
)。 - 緩存組件行為:使用
<keep-alive>
包裹的組件,在切換時不會被銷毀,而是進入“緩存狀態”(deactivated
),再次進入時直接恢復(activated
),避免重復渲染和數據請求。
二、基礎用法(??)
1. 全局緩存所有路由組件
<!-- App.vue -->
<router-view v-slot="{ Component }"><keep-alive><component :is="Component" /></keep-alive>
</router-view>
2. 緩存特定組件(推薦)
通過 include
/exclude
指定緩存組件名稱(組件的 name
選項):
<!-- 只緩存 Home 和 User 組件 -->
<keep-alive include="Home,User">//include:組件名<router-view />
</keep-alive><!-- 排除 Login 組件 -->
<keep-alive exclude="Login"><router-view />
</keep-alive>
3. 動態緩存(通過路由元信息)
在路由配置中添加 meta.keepAlive
,動態控制是否緩存:
// router.js
const routes = [{path: '/home',component: Home,meta: { keepAlive: true } // 需要緩存},{path: '/detail',component: Detail,meta: { keepAlive: false } // 不需要緩存}
];
<!-- App.vue -->
<router-view v-slot="{ Component }"><keep-alive><component :is="Component" v-if="$route.meta.keepAlive" /></keep-alive><component :is="Component" v-if="!$route.meta.keepAlive" />
</router-view>
語法與作用說明
在 Vue 中,
<keep-alive>
組件的include
屬性用于指定需要緩存的組件名稱,值可以是字符串、正則表達式,也可以是數組(數組里放組件名稱字符串) 。你代碼里的寫法:<keep-alive :include="['News','Message']"> <router-view></router-view> </keep-alive>
表示:僅緩存名稱為
News
和Message
的組件,當這兩個組件在<router-view>
中切換時,會被緩存(組件實例不會銷毀,再次進入時不會重新執行創建階段的鉤子,而是觸發activated
等緩存相關鉤子 ),其他未匹配名稱的組件則不會被緩存。關鍵前提條件
- 組件需有
name
選項:News
和Message
組件必須在自身定義中顯式聲明name
,且名稱要和include
里的字符串嚴格一致,
示例:// News.vue export default { name: 'News', // 必須聲明,且和 include 里的 'News' 一致 // ... }// Message.vue export default { name: 'Message', // ... }
如果是單文件組件未手動寫
name
,Vue 會默認將文件名作為name
(比如News.vue
會默認name: 'News'
),但為了清晰和避免意外,建議手動聲明。
- 配合路由使用場景: 這種寫法通常用于在路由切換時,緩存特定的頁面級組件(即通過
router-view
渲染的組件 )。比如News
和Message
是兩個路由組件,通過路由配置映射到不同路徑,當在這兩個路由間切換時,就能利用
keep-alive
緩存它們的狀態。常見擴展用法對比
- 字符串形式:
include="News"
,只能緩存一個組件,適合單一目標場景。- 正則形式:
:include="/News|Message/"
(需結合v-bind
綁定,因為是 JavaScript 表達式 ),用正則匹配組件名稱,靈活但相對難維護。- 數組形式(你代碼里的寫法):
:include="['News','Message']"
,清晰列出要緩存的組件,適合明確知道緩存范圍的場景,也是實際項目里常用的方式。只要滿足上述組件
name
匹配等條件,你的寫法是合法且推薦的,能精準控制緩存范圍,避免不必要的組件緩存,節省內存、提升性能。
核心區別:靜態字符串 vs 動態綁定數組
寫法 | 語法類型 | 解析方式 |
---|---|---|
include="Home,User,Product" | 靜態字符串 | Vue 會直接將字符串按逗號分割為數組 ['Home', 'User', 'Product'] |
:include="['Home','User']" | 動態綁定 JavaScript 數組 | 通過 v-bind 綁定 JS 表達式,需在 Vue 實例中定義或直接寫數組字面量 |
三、緩存組件的生命周期鉤子
activated
:組件被激活時觸發(首次加載或從緩存中恢復)。deactivated
:組件被緩存時觸發(離開但不銷毀)。
典型應用:在 activated
中判斷是否需要重新加載數據:
export default {data() {return {data: null,loaded: false};},activated() {if (!this.loaded) {this.fetchData(); // 只在首次加載或數據過期時請求this.loaded = true;}},methods: {fetchData() {// API 請求...}}
};
四、適用場景
- 頻繁切換的頁面:如標簽頁(Tab),避免每次切換都重新渲染。
- 數據加載耗時的頁面:如商品詳情頁,緩存后二次訪問無需重新請求數據。
- 需要保存狀態的表單:如多步驟表單,切換步驟時保留已填寫內容。
五、注意事項
- 內存占用:過多緩存組件會增加內存開銷,建議僅緩存關鍵頁面。
- 數據更新:緩存組件不會觸發
mounted
,需在activated
中處理數據更新。 - 組件復用問題:動態路由(如
/user/:id
)切換不同參數時,組件會復用而不觸發activated
,需通過watch
監聽$route
變化:watch: {$route() {this.fetchData(); // 路由參數變化時重新加載} }
六、高級用法
1. 結合 max
屬性限制緩存數量
<keep-alive max="3"> <!-- 最多緩存 3 個組件 --><router-view />
</keep-alive>
2. 動態控制緩存狀態
通過修改路由元信息或組件 name
,在運行時動態決定是否緩存:
// 導航守衛中動態設置
router.beforeEach((to, from, next) => {if (to.name === 'Detail' && from.name === 'List') {to.meta.keepAlive = true; // 從列表頁進入詳情頁時緩存}next();
});
七、總結
緩存路由組件是優化 SPA 性能的重要手段,通過 <keep-alive>
實現組件復用,避免重復渲染和數據請求。合理使用 include
/exclude
、路由元信息及生命周期鉤子,能在提升體驗的同時避免內存問題。
案例
以下是關于 Vue Router 核心特性的綜合解析,通過 電商商品詳情頁 案例串聯所有知識點:
案例場景
假設你正在開發一個電商網站,需要實現以下功能:
- 從商品列表頁點擊商品,跳轉到詳情頁(攜帶商品 ID)。
- 詳情頁包含 基本信息、用戶評價、相關推薦 三個子頁面(嵌套路由)。
- 評價頁支持按時間/評分篩選(query 參數)。
- 商品詳情頁需要緩存,避免重復加載數據。
1. 路由配置(router.js
)
const routes = [// 商品列表頁{ path: '/products', component: ProductsList },// 商品詳情頁(動態路由 + 嵌套路由){path: '/product/:id', // params 參數:商品 IDname: 'ProductDetail', // 命名路由component: ProductDetail,props: true, // 啟用 props 接收 paramschildren: [{ path: '', redirect: 'info' }, // 默認子路由{ path: 'info', component: ProductInfo },{ path: 'reviews', component: ProductReviews },{ path: 'related', component: RelatedProducts }]}
];
2. 路由傳參與導航
(1)query 參數(篩選條件)
<!-- 商品評價頁:篩選按鈕 -->
<router-link :to="{ name: 'ProductDetail', params: { id: productId }, query: { sort: 'time' } }"
>按時間排序
</router-link><!-- 在組件中獲取 query 參數 -->
export default {computed: {sortType() {return this.$route.query.sort || 'default';}}
}
(2)命名路由 + params 參數(商品 ID)
<!-- 商品列表項:跳轉到詳情頁 -->
<router-link :to="{ name: 'ProductDetail', params: { id: item.id } }"
>{{ item.name }}
</router-link><!-- 編程式導航(按鈕點擊) -->
methods: {goToDetail() {this.$router.push({name: 'ProductDetail',params: { id: this.selectedId }});}
}
(3)路由的 props 配置(簡化參數接收)
// 路由配置
{path: '/product/:id',component: ProductDetail,props: true // 將 params 轉為組件 props
}// 在 ProductDetail 組件中直接接收
export default {props: ['id'],mounted() {this.fetchProductData(this.id);}
}
3. router-link 的 replace 屬性
<!-- 使用 replace 替換當前歷史記錄,禁止后退 -->
<router-link :to="{ name: 'ProductDetail', params: { id } }"replace
>立即購買
</router-link>
4. 緩存路由組件(keep-alive
)
<!-- App.vue:緩存商品詳情頁 -->
<router-view v-slot="{ Component }"><keep-alive include="ProductDetail"><component :is="Component" /></keep-alive>
</router-view><!-- 被緩存組件的生命周期鉤子 -->
export default {activated() {// 組件被激活時觸發(緩存后首次加載或重新顯示)if (!this.$route.meta.loaded) {this.fetchData(); // 只在首次加載時請求數據this.$route.meta.loaded = true;}},deactivated() {// 組件被緩存時觸發(隱藏但不銷毀)}
}
5. 完整流程圖
商品列表頁(/products)└── 點擊商品(攜帶 id 參數)↓
商品詳情頁(/product/123)├── 默認顯示:基本信息(/product/123/info)├── 切換到評價頁(/product/123/reviews?sort=time)│ └── query 參數控制篩選邏輯└── 切換到相關推薦(/product/123/related)[緩存機制]
當從詳情頁跳轉到其他頁面時,詳情頁組件不會銷毀,
再次返回時直接顯示緩存內容,無需重新加載數據。
核心知識點總結
特性 | 作用 | 示例 |
---|---|---|
query 參數 | 用于傳遞可選參數(如篩選條件),顯示在 URL 中(?sort=time )。 | <router-link :to="{ query: { sort: 'time' } }"> |
命名路由 | 為路由定義名稱,避免硬編碼路徑,提高可維護性。 | name: 'ProductDetail' + this.$router.push({ name: '...' }) |
params 參數 | 用于傳遞必需參數(如 ID),通過動態路由(:id )接收。 | path: '/product/:id' + this.$route.params.id |
props 配置 | 將 params 轉為組件 props,解耦組件與路由。 | props: true + export default { props: ['id'] } |
replace 屬性 | 替換當前歷史記錄,禁止返回上一頁。 | <router-link replace> |
緩存路由組件 | 使用 keep-alive 緩存組件狀態,避免重復渲染。 | <keep-alive include="ProductDetail"> + activated() 生命周期鉤子 |
兩個新的生命周期鉤子
- ** 作用**:路由組件所獨有的兩個鉤子,用于捕獲路由組件的激活狀態。
- 具體名字:
activated
路由組件被激活時觸發。deactivated
路由組件失活時觸發。
Vue UI組件庫
一、移動端組件庫
庫名 | 特點 | 技術棧 | 官網地址 | 適用場景 |
---|---|---|---|---|
Vant | 有贊出品,更新活躍,組件全 | Vue 2/3 | https://vant-contrib.gitee.io/vant/ | 電商、表單、中大型項目 |
NutUI | 京東出品,輕量高效 | Vue 2/3 | https://nutui.jd.com/ | 快速迭代項目 |
Cube UI | 滴滴開源,定制性強 | Vue 2 | https://didi.github.io/cube-ui/ | 需深度定制的移動端項目 |
Mint UI | 經典老庫(維護停滯) | Vue 2 | https://github.com/ElemeFE/mint-ui | 舊項目維護(慎用于新項目) |
二、PC 端組件庫
庫名 | 特點 | 技術棧 | 官網地址 | 適用場景 |
---|---|---|---|---|
Element UI | 元老級,文檔完善 | Vue 2 | https://element.eleme.cn/ | 企業后臺、管理系統 |
Element Plus | Element 官方 Vue 3 版本 | Vue 3 | https://element-plus.org/ | 新項目(Vue 3 技術棧) |
View UI | 原 iView,設計現代 | Vue 2/3 | https://www.iviewui.com/ | 中后臺系統、數據可視化 |
Ant Design Vue | 阿里系,組件豐富 | Vue 2/3 | https://www.antdv.com/ | 復雜業務系統、中臺產品 |
三、跨端/全場景組件庫
庫名 | 特點 | 技術棧 | 官網地址 | 適用場景 |
---|---|---|---|---|
Naive UI | 全場景,性能優異 | Vue 3 | https://www.naiveui.com/ | 中大型 Web 應用(Vue 3) |
Arco Design | 字節跳動出品,設計統一 | Vue 2/3 | https://arco.design/vue | 企業級產品、多端一致性需求 |
四、使用建議
-
技術棧匹配:
- Vue 2:選 Element UI、Vant、View UI
- Vue 3:選 Element Plus、Naive UI、Ant Design Vue
-
場景選擇:
- 電商/移動端:Vant(功能最全)
- 企業后臺:Element UI/Plus(穩定)或 Ant Design Vue(組件豐富)
- 快速開發:NutUI(體積小)或 View UI(設計現代)
-
避坑指南:
- 避免在新項目中使用 Mint UI(已停止維護)
- 注意組件庫與 Vue 版本的兼容性
- 按需引入組件以減小打包體積(參考各庫文檔)
五、快速上手示例(Vant)
# 安裝
npm i vant@next -S # Vue 3 項目
npm i vant -S # Vue 2 項目# 按需引入(推薦)
npm i unplugin-vue-components unplugin-auto-import -D
// vite.config.js
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'export default defineConfig({plugins: [AutoImport({resolvers: [VantResolver()],}),Components({resolvers: [VantResolver()],}),],
})