Vue2 + vue-router
在 Vue 2 中使用 vue-router 可以方便地管理單頁面應用(SPA)中的路由。理解 vue-router 的生命周期和懶加載機制對于構建高效的 Vue 應用至關重要。以下是一些關鍵點和示例代碼來幫助你理解這些概念。
Vue Router 的生命周期
vue-router 提供了多個與路由相關的生命周期鉤子,這些鉤子可以在不同的時機被調用,以滿足需求。
全局守衛
1、beforeEach:路由變化之前調用。
2、beforeResolve:在 beforeEach 之后,在路由被確認之前調用。
3、afterEach:路由變化之后調用。
路由獨享守衛
1、beforeEnter:在路由配置中直接定義。
組件內的守衛
1、beforeRouteEnter:進入路由之前調用,不能訪問 this。
2、beforeRouteUpdate:路由參數變化時調用。
3、beforeRouteLeave:離開當前路由時調用。
示例代碼
以下是一個簡單的示例,展示了如何在 Vue 2 項目中使用 vue-router 的生命周期鉤子:
// router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import Home from '@/components/Home.vue';
import About from '@/components/About.vue';Vue.use(Router);const router = new Router({routes: [{path: '/',name: 'Home',component: Home,beforeEnter: (to, from, next) => {console.log('Entering Home route');next();}},{path: '/about',name: 'About',component: About,beforeEnter: (to, from, next) => {console.log('Entering About route');next();}}]
});// 全局守衛
router.beforeEach((to, from, next) => {console.log('Global beforeEach guard');next();
});router.afterEach((to, from) => {console.log('Global afterEach hook');
});export default router;
組件內的守衛:
<template><div><h1>Home Page</h1><!-- 其他模板內容 --></div>
</template><script>
export default {name: 'Home',// 組件內的守衛 - 進入路由之前調用beforeRouteEnter(to, from, next) {console.log('Entering Home route...');// 注意:在這里你不能訪問組件實例(this)next(vm => {// 當導航被確認時,并且組件實例被創建后,// 你可以通過 `vm` 訪問組件實例console.log('Access to component instance via `vm`:', vm);});},// 組件內的守衛 - 路由參數變化時調用beforeRouteUpdate(to, from, next) {console.log('Route to Home updated...');// 在這里你可以訪問組件實例(this)next();},// 組件內的守衛 - 離開當前路由時調用beforeRouteLeave(to, from, next) {console.log('Leaving Home route...');// 你可以在這里提示用戶保存更改,或者執行其他邏輯const answer = window.confirm('Do you really want to leave? You have unsaved changes!');if (answer) {next();} else {next(false); // 阻止導航}},// 其他組件選項...
};
</script><style scoped>
/* 樣式內容 */
</style>
在上面的示例中,beforeRouteEnter 守衛在路由進入組件之前被調用。由于此時組件實例尚未被創建,因此你不能訪問 this。但是,next 函數可以接收一個回調函數,該回調函數將在組件實例被創建后被調用,并且可以通過該回調函數的參數訪問組件實例。
beforeRouteUpdate 守衛在路由參數變化時被調用,此時組件實例已經存在,因此你可以訪問 this。
beforeRouteLeave 守衛在離開當前路由時被調用,你可以在這里提示用戶保存更改,或者執行其他邏輯。如果調用 next(false),則可以阻止導航。
請注意,在 beforeRouteEnter 和 beforeRouteUpdate 守衛中,next 函數必須被調用,否則導航將被掛起。而在 beforeRouteLeave 守衛中,如果不調用 next,則導航也會被掛起,但通常你會根據用戶的操作來調用 next(true) 或 next(false)。
懶加載實現
// router/index.js
import Vue from 'vue';
import Router from 'vue-router';Vue.use(Router);const router = new Router({routes: [{path: '/',name: 'Home',// 使用動態 import() 實現懶加載component: () => import(/* webpackChunkName: "home" */ '@/components/Home.vue'),beforeEnter: (to, from, next) => {console.log('Entering Home route');next();}},{path: '/about',name: 'About',component: () => import(/* webpackChunkName: "about" */ '@/components/About.vue'),beforeEnter: (to, from, next) => {console.log('Entering About route');next();}}]
});// 全局守衛
router.beforeEach((to, from, next) => {console.log('Global beforeEach guard');next();
});router.afterEach((to, from) => {console.log('Global afterEach hook');
});export default router;
在上述代碼中,component 屬性被替換為返回一個 Promise 的函數,該 Promise 解析為組件。webpackChunkName 是一個特殊的注釋,用于在 Webpack 中為這些動態加載的模塊命名,從而生成更具可讀性的文件名。
Vue3 + vue-router
在 Vue 3 中,vue-router 的生命周期與 Vue 2 類似,但有一些細微的差別和新增的功能。同時,懶加載(也稱為代碼拆分)是優化 Vue 應用性能的一種重要手段,特別是在處理大型單頁應用(SPA)時。
Vue Router 的生命周期
在 Vue Router 中,有幾個關鍵的生命周期鉤子(也稱為導航守衛),它們允許你在路由變化的不同階段執行代碼。這些鉤子包括:
全局守衛:
1、beforeEach:在每次路由改變之前調用。
2、beforeResolve:在路由解析之前調用,但在全局組件守衛和異步組件被解析之后。
3、afterEach:在每次路由改變之后調用(不接收 next 函數)。
全局守衛在整個應用中只定義一次,通常用于權限驗證、日志記錄等。
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';const routes = [{path: '/',name: 'Home',component: Home},{path: '/about',name: 'About',component: About}
];const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes
});// 全局前置守衛
router.beforeEach((to, from, next) => {console.log('Global beforeEach guard');// 在這里可以添加權限驗證等邏輯next();
});// 全局解析守衛
router.beforeResolve((to, from, next) => {console.log('Global beforeResolve guard');next();
});// 全局后置鉤子
router.afterEach((to, from) => {console.log('Global afterEach hook');// 在這里可以添加日志記錄等邏輯
});export default router;
路由獨享守衛:
1、beforeEnter:在路由配置中直接定義,只在進入該路由時調用。
路由守衛是定義在單個路由對象上的鉤子,可以用于該路由的特定邏輯。
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';const routes = [{path: '/',name: 'Home',component: Home,beforeEnter: (to, from, next) => {console.log('Before enter Home');next();}},{path: '/about',name: 'About',component: About,beforeEnter: (to, from, next) => {console.log('Before enter About');// 可以添加邏輯,比如檢查用戶是否登錄next();}}
];const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes
});export default router;
組件內守衛:
1、beforeRouteEnter:在進入路由組件之前調用(無法訪問組件實例 this)。
2、beforeRouteUpdate:在路由參數變化時調用(可以訪問組件實例 this)。
3、beforeRouteLeave:在離開路由組件之前調用(可以訪問組件實例 this)。
組件內的守衛是定義在 Vue 組件內部的鉤子,用于處理該組件的路由變化。
<!-- Home.vue -->
<template><div>Home Page</div>
</template><script>
export default {name: 'Home',beforeRouteEnter(to, from, next) {console.log('Home beforeRouteEnter');next();},beforeRouteUpdate(to, from, next) {console.log('Home beforeRouteUpdate');// 僅在路由參數變化時觸發next();},beforeRouteLeave(to, from, next) {console.log('Home beforeRouteLeave');// 可以添加確認離開的邏輯next();}
};
</script>
在 Vue 3 的 script setup 語法糖中
import { onBeforeRouteLeave, onBeforeRouteUpdate } from ‘vue-router’;
可以直接引用,也可以通過Vue Router 提供的 useRoute 和 useRouter 的組合式 API 和 onMounted、onBeforeUnmount 等 Vue 的生命周期鉤子來實現類似的功能。
懶加載實現
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';const routes = [{path: '/',name: 'Home',// 使用動態導入語法懶加載 Home 組件component: () => import('../views/Home.vue'),},{path: '/about',name: 'About',// 使用動態導入語法懶加載 About 組件component: () => import('../views/About.vue'),},// 其他路由配置...
];const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes,
});export default router;
Vue3 和 新的 router 版本新加了
1、 滾動行為管理:
你可以通過scrollBehavior配置選項來自定義滾動行為。例如,你可以保持之前的滾動位置,或者在路由跳轉時滾動到頁面頂部。
scrollBehavior方法接收一個到目標路由和當前路由的對象參數,并返回一個包含滾動位置信息的對象。
例如:
const router = createRouter({history: createWebHistory(),routes,scrollBehavior(to, from, savedPosition) {if (savedPosition) {return savedPosition} else {return { x: 0, y: 0 } // 滾動到頁面頂部}}
})
2、組合式API的集成:
Vue 3引入了組合式API,這允許你以更靈活和可復用的方式組織組件邏輯。vue-router 4也相應地提供了與組合式API集成的功能。
你可以使用useRoute鉤子來訪問當前路由的狀態(如當前路由的路徑、參數、查詢等),以及使用useRouter鉤子來訪問路由實例(如進行編程式導航)。
例如:
import { useRoute, useRouter } from 'vue-router'export default {setup() {const route = useRoute()const router = useRouter()// 訪問當前路由的路徑const currentPath = route.path// 進行編程式導航const navigateTo = (path) => {router.push(path)}return {currentPath,navigateTo}}
}
3、路由懶加載:
雖然懶加載在 Vue 2 中就已經存在,但 Vue 3 和 vue-router 4 提供了更簡潔和易用的語法來實現路由懶加載。你可以使用動態導入(import())語法來按需加載路由組件。
**Vue2和3 不同點
在Vue 2中,通常使用new VueRouter()來創建路由實例。
在Vue 3中,你需要使用createRouter函數來創建路由實例,并傳入一個包含history和routes配置對象的參數。例如: