首頁 > 軟體

vue的路由守衛和keep-alive後生命週期詳解

2022-03-08 19:00:03

Vue-Router懶載入

1、箭頭函數+import

const List = () => import('@/components/list.vue')
const router = new VueRouter({
  routes: [
    { path: '/list', component: List }
  ]
})

2、箭頭函數+require

const router = new Router({
  routes: [
   {
     path: '/list',
     component: resolve => require(['@/components/list'], resolve)
   }
  ]
})

如何定義動態路由

param方式

  • 設定路由格式:/router/:id
  • 傳遞的方式:在path後面跟上對應的值
  • 傳遞後形成的路徑:/router/123

路由定義

//在APP.vue中
<router-link :to="'/user/'+userId" replace>使用者</router-link>    
//在index.js
{
   path: '/user/:userid',
   component: User,
},

路由跳轉

// 方法1:<router-link :to="{ name: 'users', params: { myname: jake }}">按鈕</router-link>// 方法2:this.$router.push({name:'users',params:{myname:jake}})// 方法3:this.$router.push// 方法1:
<router-link :to="{ name: 'users', params: { myname: jake }}">按鈕</router-link>
// 方法2:
this.$router.push({name:'users',params:{myname:jake}})
// 方法3:
this.$router.push('/user/' + jake)

引數獲取 :通過 $route.params.userid 獲取傳遞的值。

query方式

  • 設定路由格式:/router,也就是普通設定。
  • 傳遞的方式:物件中使用query的key作為傳遞方式。
  • 傳遞後形成的路徑:/route?id=123

路由定義

//方式1:直接在router-link 標籤上以物件的形式
<router-link :to="{path:'/profile',query:{name:'why',age:28,height:188}}">檔案</router-link>
// 方式2:寫成按鈕以點選事件形式
<button @click='profileClick'>我的</button>    
profileClick(){
  this.$router.push({
    path: "/profile",
    query: {
        name: "kobi",
        age: "28",
        height: 198
    }
  });
}

跳轉方法

// 方法1:
<router-link :to="{ name: 'users', query: { uname: james }}">按鈕</router-link>
// 方法2:
this.$router.push({ name: 'users', query:{ uname:james }})
// 方法3:
<router-link :to="{ path: '/user', query: { uname:james }}">按鈕</router-link>
// 方法4:
this.$router.push({ path: '/user', query:{ uname:james }})
// 方法5:
this.$router.push('/user?uname=' + jsmes)

獲取引數:通過$route.query 獲取傳遞的值

Vue-Router導航守衛

有的時候,需要通過路由來進行一些操作,比如最常見的登入許可權驗證,當用戶滿足條件時,才讓其進入導航,否則就取消跳轉,並跳到登入頁面讓其登入。 為此有很多種方法可以植入路由的導航過程:全域性的,單個路由獨享的,或者元件級的。

全域性路由勾點

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

  • router.beforeEach 全域性前置守衛 進入路由之前。
  • router.beforeResolve 全域性解析守衛,在beforeRouteEnter呼叫之後呼叫。
  • router.afterEach 全域性後置勾點 進入路由之後。

to、from、next這三個引數:

to和from是將要進入和將要離開的路由物件,路由物件指的是平時通過this.$route獲取到的路由物件。next:Function 這個引數是個函數,且必須呼叫,否則不能進入路由(頁面空白)。

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

router.beforeEach

router.beforeEach是全域性前置守衛,進入路由之前。

router.beforeEach((to, from, next) => {  
    let ifInfo =Vue.prototype.$common.getSession('userData');  // 判斷是否登入的儲存資訊
    if (!ifInfo) { 
        // sessionStorage裡沒有儲存user資訊    
        if (to.path == '/') { 
            //如果是登入頁面路徑,就直接next()      
            next();    
        } else { 
            //不然就跳轉到登入      
            Message.warning("請重新登入!");     
            window.location.href = Vue.prototype.$loginUrl;    
        }  
    } else {    
        return next();  
    }
})

路由獨享守衛

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

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

元件內的守衛

beforeRouterEnter

beforeRouterEnter不能存取this是因為勾點在元件範例還沒被建立的時候呼叫,所以不能獲取元件範例 this,可以通過傳一個回撥給next來存取元件範例 。

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

beforeRouteUpdate

  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,但是該元件被複用時呼叫 可以存取元件範例 `this`
    // 舉例來說,對於一個帶有動態引數的路徑 /user/:id,在 /user/1 和 /user/2 之間跳轉的時候,
    // 由於會渲染同樣的 user 元件,因此元件範例會被複用。而這個勾點就會在這個情況下被呼叫。
  }

beforeRouteLeave

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

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

Vue路由勾點在生命週期函數的體現

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

  • 觸發進入其他路由。
  • 呼叫要離開路由的元件守衛beforeRouteLeave
  • 呼叫全域性前置守衛∶ beforeEach
  • 在重用的元件裡呼叫 beforeRouteUpdate
  • 呼叫路由獨享守衛 beforeEnter
  • 解析非同步路由元件。
  • 在將要進入的路由元件中呼叫 beforeRouteEnter
  • 呼叫全域性解析守衛 beforeResolve
  • 導航被確認。
  • 呼叫全域性後置勾點的 afterEach 勾點。
  • 觸發DOM更新(mounted)。
  • 執行beforeRouteEnter 守衛中傳給 next 的回撥函數。

keep-alive

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

檔案:和 相似, 是一個抽象元件:它自身不會渲染一個 DOM 元素,也不會出現在父元件鏈中。

生命週期勾點

在被keep-alive包含的元件/路由中,會多出兩個生命週期的勾點: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之前:兩個keep-alive標籤+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版本之後:      Vue新增了兩個屬性配合keep-alive來有條件地快取 路由/元件。

  • include:匹配的 路由/元件 會被快取
  • exclude:匹配的 路由/元件 不會被快取(優先順序大)

include和exclude支援三種方式來有條件的快取路由:採用逗號分隔的字串形式,正則形式,陣列形式。正則和陣列形式,必須採用v-bind形式來使用。

<keep-alive include="a,b">//逗號分隔形式
  <component :is="view"></component>
</keep-alive>

觸發勾點的完整順序

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

  • beforeRouteLeave:路由元件的元件離開路由前勾點,可取消路由離開。
  • beforeEach: 路由全域性前置守衛,可用於登入驗證、全域性路由loading等。
  • beforeEnter: 路由獨享守衛
  • beforeRouteEnter: 路由元件的元件進入路由前勾點。
  • beforeResolve:路由全域性解析守衛
  • afterEach:路由全域性後置勾點
  • beforeCreate:元件生命週期,不能存取this。
  • created:元件生命週期,可以存取this,不能存取dom。
  • beforeMount:元件生命週期
  • deactivated: 離開快取元件a,或者觸發a的beforeDestroydestroyed元件銷燬勾點。
  • mounted:存取/操作dom。
  • activated:進入快取元件,進入a的巢狀子元件(如果有的話)。
  • 執行beforeRouteEnter回撥函數next。

其實大部分的生命週期勾點函數不會被用到,但有幾點我們需要注意:

1.ajax請求最好放在created裡面,此時可以存取到this,請求返回資料可以放在data裡面。

2.關於dom的操作要放在mounted裡面,在mounted前面存取dom會是undefined,因為還沒渲染完成。

3.每次進入或離開元件需要一些操作時:

  • 不快取

進入的時候可以用createdmounted勾點,離開的時候用beforeDestorydestroyed勾點,beforeDestory可以存取this,destroyed可以存取this。

  • 快取了的元件:

快取了元件之後,再次進入元件不會觸發beforeCreate、created 、beforeMount、 mounted,如果你想每次進入元件都做一些事情的話,你可以放在activated進入快取元件的勾點中。同理:離開快取元件的時候,beforeDestroy和destroyed並不會觸發,可以使用deactivated離開快取元件的勾點來代替。

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!    


IT145.com E-mail:sddin#qq.com