vue-router 導航鉤子
因為我是初學者,所以本文主要是對vue-router導航鉤子官方文件 進行了稍微的解釋,以及加了些栗子方便理解。
什麼是導航鉤子?官方解釋:
正如其名,vue-router 提供的導航鉤子主要用來攔截導航,讓它完成跳轉或取消。有多種方式可以在路由導航發生時執行鉤子:全域性的,單個路由獨享的,或者元件級的。
簡言之就是用來監聽URL改變事件的,當URL發生改變的時候就觸發 vue-router 的導航鉤子。
全域性鉤子
你可以使用 beforeEach 註冊一個全域性的 before 鉤子:
const router = new VueRouter({ ... }); router.beforeEach((to, from, next) => { // ... next(); // 不寫這個那就是說這個導航鉤子一直都不會 resolve 完,導航就一直處於 等待中 });
當一個導航觸發時,全域性的 before 鉤子按照建立順序呼叫。鉤子是非同步解析執行,此時導航在所有鉤子 resolve 完之前一直處於 等待中。
每個鉤子方法接收三個引數:
-
to: Route: 即將要進入的目標 路由物件
-
from: Route: 當前導航正要離開的 路由物件,to 和 from 都是一個路由物件,所以你完全可以使用它們來做一些操作。
-
next: Function: 一定要呼叫該方法來 resolve 這個鉤子。這個方法是給你的,直接用就行了。執行效果依賴 next 方法的呼叫引數。
-
next(): 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。
-
next(false): 中斷當前的導航。如果瀏覽器的 URL 改變了(可能是使用者手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。就是說給 next 方法一個 false 引數的話,vue-router 會中斷當前的導航強制回到 from 的地址,無論你怎麼手動修改地址都沒用,就是不讓你跳轉。
-
next( '/' ) 或者 next({ path: '/' }) : 跳轉到一個不同的地址。當前的導航被中斷,然後進行一個新的導航。不過這個東西要小心用,因為它也會觸發鉤子的
-
確保要呼叫 next 方法,否則鉤子就不會被 resolved。
一個簡單的栗子,廢話不多少下面看:
router1.vue
<template>
<h3>Here is router-1</h3>
</template>
router2.vue
<template>
<h3>Welcome to router-2</h3>
</template>
router3.vue
<template>
<h3>Get out here</h3>
</template>
app.vue
<template>
<div>
<router-link to="/r1">Go to router-1</router-link>
<router-link to="/r2">Go to router-2</router-link>
<router-link to="/r3">Go to router-3</router-link>
<router-view></router-view>
</div>
</template>
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>myVue</title>
</head>
<body>
<div id="app">
<app />
</div>
</body>
</html>
index.js
// 引入 vue 和 vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
import app from './components/app.vue'
import router1 from './components/router1.vue'
import router2 from './components/router2.vue'
import router3 from './components/router3.vue'
// vue-router光是引進來是沒用的,還需要使用
Vue.use(VueRouter);
const routes = [{
path: '/r1',
component: router1
}, {
path: '/r2',
component: router2
}, {
path: '/r3',
component: router3
}];
const router = new VueRouter({
routes
});
// 全域性鉤子
router.beforeEach((to, from, next) => {
if (to.path == '/r2' || from.path == '/r2') {
alert('Go to ' + to.path);
next();
} else {
// next({path: 'url'}) 因為這個也會觸發鉤子,所以要小心用喔.
// 如果這裡寫的不是 '/r2' 而是 '/' 或者其他,那麼可能會導致死迴圈或者報錯,可以自己試試
next({path: '/r2'});
}
});
new Vue({
el: '#app',
router,
components: {
app
}
});
這個栗子中,全域性鉤子說明了如果不是跳轉到 '/r2' 路徑或者不是從 '/r2' 路徑路由到其他路徑的話,vue-router 就會自動地路由到 '/r2'。
效果:
同樣可以註冊一個全域性的 after 鉤子,不過它不像 before 鉤子那樣,after 鉤子沒有 next 方法,不能改變導航:
router.afterEach(route => {
// do something
})
afterEach 的 route 路由物件對應 beforeEach 的 to 路由物件,這裡沒有栗子,它表示導航已經確定了,看看你還有什麼想要做的。
某個路由獨享的鉤子
你可以在路由配置上直接定義 beforeEnter 鉤子:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
next(); // 同樣的不加的話導航就一直是等待中哦
}
}
]
})
引數一樣,用法也是一樣的,兩個路由物件和一個 next() 方法,這裡沒有栗子,可以自己玩玩。
元件內的鉤子
最後,你可以在路由元件內直接定義以下路由導航鉤子:
beforeRouteEnter
- beforeRouteUpdate (2.2新增)
beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染該元件的對應路由被 confirm 前呼叫
// 不!能!獲取元件例項 `this`
// 因為當鉤子執行前,元件例項還沒被建立,那怎麼辦?下面解釋
next()
},
beforeRouteUpdate (to, from, next) {
// 在當前路由改變,但是該元件被複用時呼叫
// 舉例來說,對於一個帶有動態引數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
// 由於會渲染同樣的 Foo 元件,因此元件例項會被複用。而這個鉤子就會在這個情況下被呼叫。
// 可以訪問元件例項 `this`
next()
},
beforeRouteLeave (to, from, next) {
// 導航離開該元件的對應路由時呼叫
// 可以訪問元件例項 `this`
next()
}
}
beforeRouteEnter 鉤子不能訪問 this,因為鉤子在導航確認前被呼叫,因此即將登場的新元件還沒被建立。
不過,你可以通過傳一個回撥給 next 來訪問元件例項。在導航被確認的時候執行回撥,並且把元件例項作為回撥方法的引數。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通過 `vm` 訪問元件例項
console.log(vm) // 感興趣的不妨將它"解剖"研究看看
})
}
你可以 在 beforeRouteLeave 中直接訪問 this 。這個 leave 鉤子通常用來禁止使用者在還未儲存修改前突然離開。可以通過 next(false) 來取消導航。
其實官方文件已經寫得很好了(畢竟vuejs的作者可是國人吶!),只需要稍微實踐一下基本都可以理解了~