路由Vue-router 的使用總結
1、關于 router-view 匹配
vue 項目使用 vue-router,所有的根級別的路由都是在 App.vue 文件中的 router-view 中渲染的。比如下面的 path: '/' 、path: '/home' 路徑匹配到的組件都是在 App.vue 文件下的 router-view 中進行渲染。
其他級別的路徑在對應的父組件的 router-view 中進行渲染。
// App.vue <div id="app"> <router-view/> </div> // 路由文件 routes: [ { path: '/', name: 'HelloWorld', component: HelloWorld, children: [ { path: 'item01', name: 'Item01', component: Item01 } ] }, { path: '/home', name: 'Home', component: Home } ]
2、導航守衛
利用導航守衛可以在路由發生變化時進行某些操作。導航守衛分為:全局守衛、路由獨享守衛、組件內守衛
示例:
const router = new VueRouter({ ... }) //全局前置守衛 router.beforeEach((to, from, next) => { // ... })
每個守衛方法接收三個參數:
-
to: Route: 即將要進入的目標 路由對象 -
from: Route: 當前導航正要離開的路由 -
next: Function,一定要調用該方法來 resolve 這個鉤子。執行效果依賴next方法的調用參數。-
next(): 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。 -
next(false): 中斷當前的導航。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器后退按鈕),那么 URL 地址會重置到from路由對應的地址。 -
next('/')或者next({ path: '/' }): 跳轉到一個不同的地址。當前的導航被中斷,然后進行一個新的導航。你可以向next傳遞任意位置對象,且允許設置諸如replace: true、name: 'home'之類的選項以及任何用在router-link的toprop 或router.push中的選項。 -
next(error): (2.4.0+) 如果傳入next的參數是一個Error實例,則導航會被終止且該錯誤會被傳遞給router.onError()注冊過的回調。
-
必須確保要調用 next 方法,否則鉤子就不會被 resolved,即路由不會跳轉。
2.1、全局守衛
2.1.1、全局前置守衛(router.beforeEach())
你可以使用 router.beforeEach 注冊一個全局前置守衛
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... }) //守衛可以有多個 router.beforeEach((to, from, next) => { // ... })
當一個導航觸發時,全局前置守衛按照創建順序調用。守衛是異步解析執行,此時導航在所有守衛 resolve 完之前一直處于 等待中。
2.1.2、全局解析守衛
在 2.5.0+ 你可以用 router.beforeResolve 注冊一個全局守衛。這和 router.beforeEach 類似,區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之后,解析守衛就被調用。
2.1.3、全局后置守衛
你也可以注冊全局后置鉤子,然而和守衛不同的是,這些鉤子不會接受 next 函數也不會改變導航本身:
router.afterEach((to, from) => { // ... })
2.2、路由獨享守衛
你可以在某個路由配置上直接定義 beforeEnter 守衛,這些守衛與全局前置守衛的方法參數是一樣的。
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
2.3、組件內守衛
2.3.1、前置守衛(beforeRouteEnter())
在渲染該組件的對應路由被 confirm 前調用。注意:該守衛內部不能獲取組件實例 `this` ,因為該守衛是在導航確認前被調用,此時組件還沒被創建。
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { //... } }
要想在該守衛內部訪問組件實例,可以給 next傳一個回調函數,在導航被確認的時候執行回調,并且把組件實例作為 next 回調函數的參數,此時就可以訪問組件實例了。
beforeRouteEnter (to, from, next) { next(vm => { // 通過 `vm` 訪問組件實例 }) }
beforeRouteEnter 是唯一支持給 next 傳遞回調的守衛。因為其他守衛比如 beforeRouteUpdate 和 beforeRouteLeave ,this 已經可用了,所以沒有必要支持傳遞回調。
2.3.2、路由改變不跳轉時的守衛(beforeRouteUpdate())
在當前路由改變,但是該組件被復用時調用。
比如,對于一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候該守衛會被觸發。由于會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用。
該守衛可以訪問組件實例 `this`。
const Foo = { template: `...`, beforeRouteUpdate (to, from, next) { // ... this.xxx = to.xxx
next(); } }
2.3.3、后置守衛(beforeRouteLeave())
該守衛在導航離開該組件的對應路由時調用。可以訪問組件實例 `this`。
const Foo = { template: `...`, beforeRouteLeave (to, from, next) { // ... this.xxx = xxx; next(); } }
這個離開守衛通常用來禁止用戶在還未保存修改前突然離開。該導航可以通過 next(false) 來取消。
beforeRouteLeave (to, from , next) { const answer = window.confirm('Do you really want to leave? you have unsaved changes!') if (answer) { next() } else { next(false) } }
2.4、完整的導航解析流程
- 導航被觸發。
- 在失活的組件里調用離開守衛。
- 調用全局的
beforeEach守衛。 - 在重用的組件里調用
beforeRouteUpdate守衛 (2.2+)。 - 在路由配置里調用
beforeEnter。 - 解析異步路由組件。
- 在被激活的組件里調用
beforeRouteEnter。 - 調用全局的
beforeResolve守衛 (2.5+)。 - 導航被確認。
- 調用全局的
afterEach鉤子。 - 觸發 DOM 更新。
- 用創建好的實例調用
beforeRouteEnter守衛中傳給next的回調函數。
3、meta 元信息的妙用
路由可以配置 meta 選項來備注路由的一些信息,利用這個元信息可以實現一些比較巧妙的功能。可以參考:https://www.bbsmax.com/A/A7zglW41J4/
4、路由懶加載(()=>import())
當打包構建應用時,JavaScript 包會變得非常大,影響頁面加載。如果我們能把不同路由對應的組件分割成不同的代碼塊,然后當路由被訪問的時候才加載對應組件,這樣就更加高效了。結合 Vue 的異步組件和 Webpack 的代碼分割功能,就能輕松實現路由組件的懶加載。
實現路由懶加載很簡單,只要照著下面寫法即可:
//路由懶加載語法: const Foo = () => import('./Foo.vue') const router = new VueRouter({ routes: [{ path: '/foo', component: Foo }] })
上面將會將 foo.vue 組件提取為一個單獨的文件,并且在被訪問到時才加載。(提示語法報錯可能是因為沒有使用syntax-dynamic-import 插件,可參考:http://www.rzrgm.cn/xiaochongchong/p/7772773.html)
在打包的時候,文件命名會根據 id 命名,每次也可能會發生改變,如果需要指定命名,可以使用Magic Comments(魔法注釋)?;蛘呤怯袝r候我們可能會想把某個路由下的所有組件都打包在同個文件 (chunk) 中,也可以使用魔法注釋來命名 chunk (需要 Webpack > 2.4):
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue') const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
由此,上面將會將三個組件都打包到 group-foo.js 文件中。

浙公網安備 33010602011771號