Vue 導航守衛(路由的生命週期)

"導航" 表示路由正在發生改變vue

vue-router 提供的導航守衛主要用來經過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程當中,他們分爲三種:git

  • 全局的
    • router.beforeEach
    • router.beforeResolve
    • router.afterEach
  • 單個路由獨享的
    • beforeEnter
  • 組件級的
    • beforeRouteEnter
    • beforeRouteUpdate
    • beforeRouteLeave

注:參數或查詢的改變並不會觸發進入/離開的導航守衛 (你能夠經過觀察 $route 對象來應對這些變化,或使用 beforeRouteUpdate 的組件內守衛。)vue-router

給一張圖直觀的看一下:
瀏覽器

圖片加載失敗!

全局前置守衛

可使用 router.beforeEach 註冊一個全局前置守衛bash

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})
複製代碼

當一個導航觸發時,全局前置守衛會按照建立順序調用。守衛是異步解析執行,此時導航在全部守衛 resolve 完以前一直處於等待中異步

參數

每一個守衛方法接收三個參數:函數

  • to:Route :即將要進入的目標 路由對象
  • from:Route :當前導航正要離開的路由
  • next:Function :必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數
    • next() 進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是 confirmed (確認的)。
    • next(false): 中斷當前的導航。若是瀏覽器的 URL 改變了 (多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。
    • next('/') 或者 next({ path: '/' }): 跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。你能夠向 next 傳遞任意位置對象,且容許設置諸如 replace: truename: 'home' 之類的選項以及任何用在 router-linkto proprouter.push 中的選項。
    • next(error): (2.4.0+) 若是傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 註冊過的回調。

確保要調用next方法,不然鉤子就不會被resolvedui

全局解析守衛

能夠用router.beforeResolve註冊一個全局守衛。這和 router.beforeEach 相似,區別是在導航被確認以前,同時在全部組件內守衛和異步路由組件被解析以後,解析守衛就被調用。this

全局後置鉤子

能夠註冊一個全局後置鉤子,然而和守衛不一樣的是,這些鉤子不會接受next 函數也不會改變導航自己spa

router.afterEach((to, from) => {
  // ...
})
複製代碼

路由獨享的守衛

能夠在路由配置上直接定義 beforeEnter 守衛:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
複製代碼

這些守衛與全局前置守衛的方法參數是同樣的。

組件內的守衛

固然,也能夠在路由組件內直接定義如下路由導航守衛:

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染該組件的對應路由被 confirm 前調用
	// 也就是進入新的組件時
    // 不能獲取組件實例 `this`
    // 由於當守衛執行前,組件實例還沒被建立
  },
  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,可是該組件被複用時調用
    // 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
    // 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。
    // 能夠訪問組件實例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該組件的對應路由時調用
    // 能夠訪問組件實例 `this`
  }
}
複製代碼

beforeRouteEnter 守衛 不能 訪問 this,由於守衛在導航確認前被調用,所以即將登場的新組件還沒被建立。

不過,你能夠經過傳一個回調給 next 來訪問組件實例。在導航被確認的時候執行回調,而且把組件實例做爲回調方法的參數。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 經過 `vm` 訪問組件實例
  })
}
複製代碼

注意 beforeRouteEnter 是支持給 next 傳遞迴調的惟一守衛。對於 beforeRouteUpdatebeforeRouteLeave 來講,this 已經可用了,因此不支持傳遞迴調,由於沒有必要了。

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}
複製代碼

beforeRouteUpdate 是在路徑發生改變時調用

這個離開守衛一般用來禁止用戶在還未保存修改前忽然離開。該導航能夠經過 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)
  }
}
複製代碼

完整的導航解析流程

1.導航被觸發
2.在失活的組件裏調用離開守衛。
3.調用全局的 beforeEach 守衛。
4.在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。
5.在路由配置裏調用 beforeEnter
6.解析異步路由組件。
7.在被激活的組件裏調用 beforeRouteEnter
8.調用全局的 beforeResolve 守衛 (2.5+)。
9.導航被確認。
10.調用全局的 afterEach 鉤子。
11.觸發 DOM 更新。
12.用建立好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。

代碼示例

//Router定義

Vue.use(Router)

const router = new Router({
    ...
})

//導航守衛

router.beforeEach((to, from, next) => {
  console.log("導航前置守衛: beforeEach,");
  next();
})
router.afterEach((to, from) => {
  console.log("導航後置守衛: afterEach,");
}) 
router.beforeResolve ((to, from, next) => {
  console.log("導航解析守衛: beforeResolve,");
  next();
})
複製代碼

組件鉤子:

export default {
  //鉤子
  beforeCreate(){
    console.log("組件鉤子: beforeCreate");
  },
  created(){
    console.log("組件鉤子: created");
  },
  beforeMount(){
    console.log("組件鉤子: beforeMount");
  },
  mounted(){
    console.log("組件鉤子: mounted");
  },
  beforeUpdate(){
    console.log("組件鉤子: beforeUpdate");
  },
  updated(){
    console.log("組件鉤子: updated");
  },
  beforeDestroy(){
    console.log("組件鉤子: beforeDestroy");
  },
  destoryed(){
    console.log("組件鉤子: destoryed");
  },
  beforeRouteEnter (to, from, next) {
    console.log("組件內部守衛: beforeRouteEnter,");
    next()
  },
  beforeRouteUpdate (to, from, next) {
    console.log("組件內部守衛: beforeRouteUpdate,");
    next()
  },
  beforeRouteLeave (to, from, next) {
    console.log("組件內部守衛: beforeRouteLeave,");
    next()
  }
}
複製代碼

執行輸出順序:

導航前置守衛: beforeEach
    組件內部守衛: beforeRouteEnter
    導航解析守衛: beforeResolve
    導航後置守衛: afterEach
    組件鉤子: beforeCreate
    組件鉤子: created
    組件鉤子: beforeMount
    組件鉤子: mounted
    //執行跳轉
    組件內部守衛: beforeRouteLeave
    導航前置守衛: beforeEach
    導航解析守衛: beforeResolve
    導航後置守衛: afterEach
    組件鉤子: beforeDestroy
複製代碼

關於 Vue組件 的生命週期與鉤子函數,請參考個人文章《Vue 生命週期與鉤子函數》


^_<

相關文章
相關標籤/搜索