1. 程式人生 > >Vue的鉤子函式[路由導航守衛、keep-alive、生命週期鉤子]詳解

Vue的鉤子函式[路由導航守衛、keep-alive、生命週期鉤子]詳解

一篇關於vue鉤子函式的文章,很實用,也解決了我的很多疑問

前言

說到Vue的鉤子函式,可能很多人只停留在一些很簡單常用的鉤子(created,mounted),而且對於裡面的區別,什麼時候該用什麼鉤子,並沒有仔細的去研究過,且Vue的生命週期在面試中也算是比較高頻的考點,那麼該如何回答這類問題,讓人有眼前一亮的感覺呢...

Vue-Router導航守衛:

有的時候,我們需要通過路由來進行一些操作,比如最常見的登入許可權驗證,當用戶滿足條件時,才讓其進入導航,否則就取消跳轉,並跳到登入頁面讓其登入。

為此我們有很多種方法可以植入路由的導航過程:全域性的, 單個路由獨享的, 或者元件級的

,推薦優先閱讀路由文件

全域性守衛

vue-router全域性有三個守衛:

  1. router.beforeEach 全域性前置守衛 進入路由之前
  2. router.beforeResolve 全域性解析守衛(2.5.0+) 在beforeRouteEnter呼叫之後呼叫
  3. router.afterEach 全域性後置鉤子 進入路由之後

使用方法

    // main.js 入口檔案
    import router from './router'; // 引入路由
    router.beforeEach((to, from, next) => { 
      next();
    });
    router.beforeResolve((to, from, next) => {
      next();
    });
    router.afterEach((to, from) => {
      console.log('afterEach 全域性後置鉤子');
    });

to,from,next 這三個引數:

to和from是將要進入和將要離開的路由物件,路由物件指的是平時通過this.$route獲取到的路由物件。

next:Function 這個引數是個函式,且必須呼叫,否則不能進入路由(頁面空白)。

  • next() 進入該路由。

  • next(false): 取消進入路由,url地址重置為from路由地址(也就是將要離開的路由地址)。

  • next 跳轉新路由,當前的導航被中斷,重新開始一個新的導航。

      我們可以這樣跳轉:next('path地址')或者next({path:''})或者next({name:''})
      且允許設定諸如 replace: true、name: 'home' 之類的選項
      以及你用在router-link或router.push的物件選項。
    

路由獨享守衛

如果你不想全域性配置守衛的話,你可以為某些路由單獨配置守衛:

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => { 
            // 引數用法什麼的都一樣,呼叫順序在全域性前置守衛後面,所以不會被全域性守衛覆蓋
            // ...
          }
        }
      ]
    })

路由元件內的守衛:

  1. beforeRouteEnter 進入路由前
  2. beforeRouteUpdate (2.2) 路由複用同一個元件時
  3. beforeRouteLeave 離開當前路由時

文件中的介紹:

  beforeRouteEnter (to, from, next) {
    // 在路由獨享守衛後呼叫 不!能!獲取元件例項 `this`,元件例項還沒被建立
  },
  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,但是該元件被複用時呼叫 可以訪問元件例項 `this`
    // 舉例來說,對於一個帶有動態引數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
    // 由於會渲染同樣的 Foo 元件,因此元件例項會被複用。而這個鉤子就會在這個情況下被呼叫。
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該元件的對應路由時呼叫,可以訪問元件例項 `this`
  }

beforeRouteEnter訪問this

因為鉤子在元件例項還沒被建立的時候呼叫,所以不能獲取元件例項 this,可以通過傳一個回撥給next來訪問元件例項 。

但是回撥的執行時機在mounted後面,所以在我看來這裡對this的訪問意義不太大,可以放在created或者mounted裡面。

    beforeRouteEnter (to, from, next) {
    console.log('在路由獨享守衛後呼叫');
      next(vm => {
        // 通過 `vm` 訪問元件例項`this` 執行回撥的時機在mounted後面,
      })
    }

beforeRouteLeave:

導航離開該元件的對應路由時呼叫,我們用它來禁止使用者離開,比如還未儲存草稿,或者在使用者離開前,將setInterval銷燬,防止離開之後,定時器還在呼叫。

    beforeRouteLeave (to, from , next) {
      if (文章儲存) {
        next(); // 允許離開或者可以跳到別的路由 上面講過了
      } else {
        next(false); // 取消離開
      }
    }

關於鉤子的一些知識:

路由鉤子函式的錯誤捕獲

如果我們在全域性守衛/路由獨享守衛/元件路由守衛的鉤子函式中有錯誤,可以這樣捕獲:

    router.onError(callback => { 
    // 2.4.0新增 並不常用,瞭解一下就可以了 
      console.log(callback, 'callback');
    });

在路由文件中還有更多的例項方法:動態新增路由等,有興趣可以瞭解一下。

跳轉死迴圈,頁面永遠空白

我瞭解到的,很多人會碰到這個問題,來看一下這段虛擬碼:

    router.beforeEach((to, from, next) => {
      if(登入){
         next()
      }else{
          next({ name: 'login' }); 
      }
    });

看邏輯貌似是對的,但是當我們跳轉到login之後,因為此時還是未登入狀態,所以會一直跳轉到login然後死迴圈,頁面一直是空白的,所以:我們需要把判斷條件稍微改一下。

    if(登入 || to.name === 'login'){ next() } // 登入,或者將要前往login頁面的時候,就允許進入路由

全域性後置鉤子的跳轉:

文件中提到因為router.afterEach不接受next函式所以也不會改變導航本身,意思就是隻能當成一個鉤子來使用,但是我自己在試的時候發現,我們可以通過這種形式來實現跳轉:

    // main.js 入口檔案
    import router from './router'; // 引入路由
    router.afterEach((to, from) => {
      if (未登入 && to.name !== 'login') {
        router.push({ name: 'login' }); // 跳轉login
      }
    });

額,通過router.beforeEach 也完全可以實現且更好,我就騷一下。

完整的路由導航解析流程(不包括其他生命週期):

  1. 觸發進入其他路由。
  2. 呼叫要離開路由的元件守衛beforeRouteLeave
  3. 呼叫局前置守衛:beforeEach
  4. 在重用的元件裡呼叫 beforeRouteUpdate
  5. 呼叫路由獨享守衛 beforeEnter
  6. 解析非同步路由元件。
  7. 在將要進入的路由元件中呼叫beforeRouteEnter
  8. 呼叫全域性解析守衛 beforeResolve
  9. 導航被確認。
  10. 呼叫全域性後置鉤子的 afterEach 鉤子。
  11. 觸發DOM更新(mounted)。
  12. 執行beforeRouteEnter 守衛中傳給 next 的回撥函式

你不知道的keep-alive[我猜你不知道]

在開發Vue專案的時候,大部分元件是沒必要多次渲染的,所以Vue提供了一個內建元件keep-alive快取元件內部狀態,避免重新渲染文件在這裡

文件:和 <transition>相似,<keep-alive> 是一個抽象元件:它自身不會渲染一個 DOM 元素,也不會出現在父元件鏈中。

用法:

快取動態元件:

<keep-alive>包裹動態元件時,會快取不活動的元件例項,而不是銷燬它們,此種方式並無太大的實用意義。

    <!-- 基本 -->
    <keep-alive>
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 多個條件判斷的子元件 -->
    <keep-alive>
      <comp-a v-if="a > 1"></comp-a>
      <comp-b v-else></comp-b>
    </keep-alive>

快取路由元件:

使用keep-alive可以將所有路徑匹配到的路由元件都快取起來,包括路由元件裡面的元件,keep-alive大多數使用場景就是這種。

    <keep-alive>
        <router-view></router-view>
    </keeo-alive>

生命週期鉤子:

這篇既然是Vue鉤子函式的專場,那肯定要扣題呀~

在被keep-alive包含的元件/路由中,會多出兩個生命週期的鉤子:activateddeactivated

文件:在 2.2.0 及其更高版本中,activated 和 deactivated 將會在 樹內的所有巢狀元件中觸發。

activated在元件第一次渲染時會被呼叫,之後在每次快取元件被啟用時呼叫

activated呼叫時機:

第一次進入快取路由/元件,在mounted後面,beforeRouteEnter守衛傳給 next 的回撥函式之前呼叫:

    beforeMount=> 如果你是從別的路由/元件進來(元件銷燬destroyed/或離開快取deactivated)=>
    mounted=> activated 進入快取元件 => 執行 beforeRouteEnter回撥

因為元件被快取了,再次進入快取路由/元件時,不會觸發這些鉤子

    // beforeCreate created beforeMount mounted 都不會觸發。

所以之後的呼叫時機是:

    元件銷燬destroyed/或離開快取deactivated => activated 進入當前快取元件 
    => 執行 beforeRouteEnter回撥
    // 元件快取或銷燬,巢狀元件的銷燬和快取也在這裡觸發

deactivated:元件被停用(離開路由)時呼叫

使用了keep-alive就不會呼叫beforeDestroy(元件銷燬前鉤子)和destroyed(元件銷燬),因為元件沒被銷燬,被快取起來了

這個鉤子可以看作beforeDestroy的替代,如果你快取了元件,要在元件銷燬的的時候做一些事情,你可以放在這個鉤子裡。

如果你離開了路由,會依次觸發:

    元件內的離開當前路由鉤子beforeRouteLeave =>  路由前置守衛 beforeEach =>
    全域性後置鉤子afterEach => deactivated 離開快取元件 => activated 進入快取元件(如果你進入的也是快取路由)
    // 如果離開的元件沒有快取的話 beforeDestroy會替換deactivated 
    // 如果進入的路由也沒有快取的話  全域性後置鉤子afterEach=>銷燬 destroyed=> beforeCreate等

那麼,如果我只是想快取其中幾個路由/元件,那該怎麼做?

快取你想快取的路由:

Vue2.1.0之前:

想實現類似的操作,你可以:

  1. 配置一下路由元資訊

  2. 建立兩個keep-alive標籤

  3. 使用v-if通過路由元資訊判斷快取哪些路由。

     <keep-alive>
         <router-view v-if="$route.meta.keepAlive">
             <!--這裡是會被快取的路由-->
         </router-view>
     </keep-alive>
     <router-view v-if="!$route.meta.keepAlive">
         <!--因為用的是v-if 所以下面還要建立一個未快取的路由檢視出口-->
     </router-view>
     //router配置
     new Router({
       routes: [
         {
           path: '/',
           name: 'home',
           component: Home,
           meta: {
             keepAlive: true // 需要被快取
           }
         },
         {
           path: '/:id',
           name: 'edit',
           component: Edit,
           meta: {
             keepAlive: false // 不需要被快取
           }
         }
       ]
     });

Vue2.1.0版本之後:

使用路由元資訊的方式,要多建立一個router-view標籤,並且每個路由都要配置一個元資訊,是可以實現我們想要的效果,但是過於繁瑣了點。

幸運的是在Vue2.1.0之後,Vue新增了兩個屬性配合keep-alive來有條件地快取 路由/元件。

新增屬性:

  • include:匹配的 路由/元件 會被快取
  • exclude:匹配的 路由/元件 不會被快取

includeexclude支援三種方式來有條件的快取路由:採用逗號分隔的字串形式,正則形式,陣列形式。

正則和陣列形式,必須採用v-bind形式來使用。

快取元件的使用方式

    <!-- 逗號分隔字串 -->
    <keep-alive include="a,b">
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 正則表示式 (使用 `v-bind`) -->
    <keep-alive :include="/a|b/">
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 陣列 (使用 `v-bind`) -->
    <keep-alive :include="['a', 'b']">
      <component :is="view"></component>
    </keep-alive>

但更多場景中,我們會使用keep-alive來快取路由

<keep-alive include='a'>
    <router-view></router-view>
</keeo-alive>

匹配規則:

  1. 首先匹配元件的name選項,如果name選項不可用。
  2. 則匹配它的區域性註冊名稱。 (父元件 components 選項的鍵值)
  3. 匿名元件,不可匹配

比如路由元件沒有name選項,並且沒有註冊的元件名。

  1. 只能匹配當前被包裹的元件,不能匹配更下面巢狀的子元件

比如用在路由上,只能匹配路由元件的name選項,不能匹配路由元件裡面的巢狀元件的name選項。

  1. 文件:<keep-alive>不會在函式式元件中正常工作,因為它們沒有快取例項。
  2. exclude的優先順序大於include

也就是說:當includeexclude同時存在時,exclude生效,include不生效。

  <keep-alive include="a,b" exclude="a">
    <!--只有a不被快取-->
    <router-view></router-view>
  </keep-alive>

當元件被exclude匹配,該元件將不會被快取,不會呼叫activateddeactivated

元件生命週期鉤子:

關於元件的生命週期,是時候放出這張圖片了:

這張圖片已經講得很清楚了,很多人這部分也很清楚了,大部分生命週期並不會用到,這裡提一下幾點:

  1. ajax請求最好放在created裡面,因為此時已經可以訪問this了,請求到資料就可以直接放在data裡面。

    這裡也碰到過幾次,面試官問:ajax請求應該放在哪個生命週期。

  2. 關於dom的操作要放在mounted裡面,在mounted前面訪問dom會是undefined

  3. 每次進入/離開元件都要做一些事情,用什麼鉤子:

  • 不快取:

    進入的時候可以用createdmounted鉤子,離開的時候用beforeDestorydestroyed鉤子,beforeDestory可以訪問thisdestroyed不可以訪問this

  • 快取了元件:

    快取了元件之後,再次進入元件不會觸發beforeCreatecreatedbeforeMountmounted如果你想每次進入元件都做一些事情的話,你可以放在activated進入快取元件的鉤子中

    同理:離開快取元件的時候,beforeDestroydestroyed並不會觸發,可以使用deactivated離開快取元件的鉤子來代替。

觸發鉤子的完整順序:

將路由導航、keep-alive、和元件生命週期鉤子結合起來的,觸發順序,假設是從a元件離開,第一次進入b元件:

  1. beforeRouteLeave:路由元件的元件離開路由前鉤子,可取消路由離開。
  2. beforeEach: 路由全域性前置守衛,可用於登入驗證、全域性路由loading等。
  3. beforeEnter: 路由獨享守衛
  4. beforeRouteEnter: 路由元件的元件進入路由前鉤子。
  5. beforeResolve:路由全域性解析守衛
  6. afterEach:路由全域性後置鉤子
  7. beforeCreate:元件生命週期,不能訪問this
  8. created:元件生命週期,可以訪問this,不能訪問dom。
  9. beforeMount:元件生命週期
  10. deactivated: 離開快取元件a,或者觸發a的beforeDestroydestroyed元件銷燬鉤子。
  11. mounted:訪問/操作dom。
  12. activated:進入快取元件,進入a的巢狀子元件(如果有的話)。
  13. 執行beforeRouteEnter回撥函式next。

結語

Vue提供了很多鉤子,但很多鉤子我們幾乎不會用到,只有清楚這些鉤子函式的觸發順序以及背後的一些限制等,這樣我們才能夠正確的使用這些鉤子,希望看了本文的同學,能對這些鉤子有更加清晰的認識,使用起來更加得心應手。


作者:OBKoro1
連結:https://juejin.im/post/5b41bdef6fb9a04fe63765f1
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

相關推薦

Vue鉤子函式[路由導航守衛keep-alive生命週期鉤子]

前言 說到Vue的鉤子函式,可能很多人只停留在一些很簡單常用的鉤子(created,mounted),而且對於裡面的區別,什麼時候該用什麼鉤子,並沒有仔細的去研究過,且Vue的生命週期在面試中也算是比較高頻的考點,那麼該如何回答這類問題,讓人有眼前一亮的感覺呢... 游

Vue鉤子函式(路由導航守衛keep-alive生命週期鉤子)

說到Vue的鉤子函式,可能很多人只停留在一些很簡單常用的鉤子(created,mounted),而且對於裡面的區別,什麼時候該用什麼鉤子,並沒有仔細的去研究過,且Vue的生命週期在面試中也算是比較高頻的考點,那麼該如何回答這類問題,讓人有眼前一亮的感覺呢… Vue-Router導航守衛:

Vue鉤子函式[路由導航守衛keep-alive生命週期鉤子]

一篇關於vue鉤子函式的文章,很實用,也解決了我的很多疑問 前言 說到Vue的鉤子函式,可能很多人只停留在一些很簡單常用的鉤子(created,mounted),而且對於裡面的區別,什麼時候該用什麼鉤子,並沒有仔細的去研究過,且Vue的生命週期在面試中也算是比較高頻的

Vue鉤子函數[路由導航keep-alive生命周期鉤子]

項目 多種方法 RoCE 添加路由 meta 自身 就會 執行 多人 前言說到Vue的鉤子函數,可能很多人只停留在一些很簡單常用的鉤子(created,mounted),而且對於裏面的區別,什麽時候該用什麽鉤子,並沒有仔細的去研究過,且Vue的生命周期在面試中也算是比較高頻

Vue鉤子函式生命週期例項

vue生命週期簡介 Vue例項有一個完整的生命週期,也就是從開始建立、初始化資料、編譯模板、掛載Dom、渲染→更新→渲染、解除安裝等一系列過程,我們稱這是Vue的生命週期。通俗說就是Vue例項從建立到銷燬的過程,就是生命週期。 在Vue的整個生命週期中,它提供了一系列的事件,可以讓我們在事件觸發時註冊js

vue2路由導航守衛鉤子函式

官方:vue-router 提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程中:全域性的, 單個路由獨享的, 或者元件級的。 所謂的Vue路由導航守衛,也就是我們常說的生命週期鉤子函式,鉤子函式的意思就是在特定的時刻,Vue會自動觸發這個方

Vue-router(5)之 路由導航守衛

app.vue <template> <div> <h1>App根元件---路由導航守衛</h1> <!-- 路由的佔位符 --> <router-view></router-view>

vue - 過濾器-鉤子函式路由

一.關於路由 1.使用vue router 本質上是宣告一種可以通過路徑進行 掛子,用子 找到對應的 template 進行頁面渲染 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4

vue2.0 實現導航守衛 --- 齊梟飛 前端開發攻城獅(路由守衛) 使用vue-router+vuex進行導航守衛

路由跳轉前做一些驗證,比如登入驗證,是網站中的普遍需求。 對此,vue-route 提供的 beforeRouteUpdate 可以方便地實現導航守衛(navigation-guards)。 導航守衛(navigation-guards)這個名字,聽起來怪怪的

vue.js生命週期鉤子過濾器互動練習001 仿留言板

需求: 呼叫介面獲取留言資料 過濾時間只取年月日 開啟網頁便執行請求 程式碼: <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /&g

Vue生命週期鉤子函式的理解

對Vue生命週期鉤子函式的理解 例項建立之後,初始化事件和生命週期,而後觸發beforeCreate。beforeCreate,當前例項建立之前,很少操作,一般用於載入動畫,比如建立一個旋轉動畫。created表示當前例項建立完成,元件、屬性等初始化完成,一般封裝一個方法,從網路請求資料

vue單頁應用中 返回列表記住上次滾動位置keep-alive快取之後更新列表資料 那點事

實踐場景需求 產品列表中,滾動到一定位置的時候,點選檢視產品資訊,後退之後,需要回到原先的滾動位置,這是常見的需求 所有頁面均在router-view中,暫時使用了keep-alive來快取所有頁面,所以進入不同分類的產品列表,和不同的產品詳情頁面,需要更新資料 首先注意: 本次實踐測試環境為pc

VueRouter和Vue生命週期(鉤子函式)

一、vue-router路由 1、介紹 vue-router是Vue的路由系統,用於定位資源的,在頁面不重新整理的情況下切換頁面內容。類似於a標籤,實際上在頁面上展示出來的也是a標籤,是錨點。   2、路由註冊 1. 定義一個路由匹配規則和路由對應元件的物件 let url = [

Vue生命週期鉤子函式

1、beforeCreate():元件例項剛剛被建立 (el和data並未初始化) 2、created():元件建立完成,屬性已繫結,但DOM還未生成,$el屬性還不存在 (完成data資料的初始化),: 例項已經建立完成之後呼叫,在這一步,例項已經完成資料觀測, 屬性和方法的運算, watch/event

Vuevue-router router.beforeEach導航守衛,陷入死迴圈

官方文件 :https://router.vuejs.org/zh/guide/advanced/navigation-guards.html 判斷瀏覽器快取是否有使用者的資訊,沒有的話跳轉登入頁。 看了官方文件,直接這樣寫了。(試了手動清除快取,再從url裡面跳登入頁,直接陷入了死迴圈)

前端框架vue.js系列(10):生命週期鉤子函式

每個vue例項在被建立之前都要經過一系列的初始化過程。例如需要設定資料監聽、編譯模板、掛載例項到dom、在資料變化時更新dom等。同時在這個過程中也會執行一些叫做生命週期鉤子的函式,給予使用者機會在一些特定的場景下新增他們自己的程式碼。 下圖說明了例項的生命週期。你不需要立

vue生命週期鉤子函式與自定義指令鉤子函式

Vue.directive('hello',{ bind:function(el){ console.log("bind時父節點為:"+el.parentNode) console.log("觸發bind指令鉤子函式") },

vue過渡動畫的生命週期/鉤子函式

 相信大家都會看到使用vue外掛的時候,那一連串的函式是什麼意思呢? vue中所有的鉤子函式: beforeCreate(建立前) created(建立後) beforeMount(載入前) mounted(載入後) beforeUpdate(更新前) up

vue.js生命週期鉤子函式及快取

生命週期 在工作中用到最多的就是created,mounted,activated,deactivated. 由於系統需要快取,使用了keep-alive

vuevue-routertransitionkeep-alive結合使用

<transition :name="name"> <keep-alive> <router-view class="router-view" v-if="$route.meta.alive"></rout