1. 程式人生 > >vue-router 導航鉤子

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的作者可是國人吶!),只需要稍微實踐一下基本都可以理解了~