keep-alive.緩存問題

對于vue的 keep-alive 組件,先簡單介紹一下:

<keep-alive> 包裹動態(tài)組件時,會緩存不活動的組件實(shí)例,而不是銷毀它們。和 <transition> 相似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現(xiàn)在父組件鏈中。當(dāng)組件在 <keep-alive> 內(nèi)被切換,它的 activated 和 deactivated 這兩個生命周期鉤子函數(shù)將會被對應(yīng)執(zhí)行。
include 和 exclude 屬性允許組件有條件地緩存。二者都可以用逗號分隔字符串、正則表達(dá)式或一個數(shù)組來表示:

<!-- 逗號分隔字符串 -->
<keep-alive include="a,b">
  <component :is="view"></component>
</keep-alive>

<!-- 正則表達(dá)式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<!-- Array (use `v-bind`) -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

匹配首先檢查組件自身的 name 選項,如果 name 選項不可用,則匹配它的局部注冊名稱(父組件 components 選項的鍵值。

在項目中,有些頁面需要緩存,有些不需要,這就需要使用keep-alive進(jìn)行相關(guān)控制,來達(dá)到效果。 一般的使用方法,可能都是下面的這種:

先在路由中配置meta: { keepAlive: true },然后

<keep-alive>
   <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view> 

根據(jù)keepAlive的值來進(jìn)行是否緩存判斷。

這種對于常規(guī)的頁面緩存是有效的。 但是在項目中,一個頁面不會一直被緩存的,有時需要重新渲染。比如,一個列表頁(a)、詳情頁(b)和詳情擴(kuò)展頁(c),a -> b頁面,a是緩存頁,b需要在每次打開時,重新渲染;b -> c頁面,此時b需要被緩存,從c返回時,需要b保持不變。 對于這種需求,目前大部分的解決方案是:通過在路由導(dǎo)航守衛(wèi)中判斷b頁面如果是前往c頁面,則需要緩存,如果前往a頁面,則b不需要緩存。

beforeRouteLeave(to, from, next) {
  if(to.path.includes('c')) {
    from.meta.keepAlive = true;
  } else {
    from.meta.keepAlive = false;
  }
    next();
  }

這種方式會出現(xiàn)一個問題: 首先,(具體例子,從上到下對于a、b、c),第一次前往c頁面時,b確實(shí)會被緩存,

image

但是我們返回a頁面,再前往b頁面時,會出現(xiàn)一個新的b緩存頁,

image

就算這不影響我們的性能,但是你繼續(xù)前往c頁面時,

image

我們之前的b被直接銷毀,導(dǎo)致返回b頁面時,會返回到第一次緩存的頁面,而且之后一直都是只回到第一次的頁面,

image

這并不是我們想要看到的。 網(wǎng)上搜羅一番,有說可以在回到a頁面時,把緩存的b頁面手動銷毀,vue提供一個vm.$destroy()的方法,但是這是不被推薦使用的,我們先試一下:

beforeRouteLeave(to, from, next) {
  if(to.path.includes('c')) {
    from.meta.keepAlive = true;
  } else {
    from.meta.keepAlive = false;
    this.$destroy();
  }
    next();
  }

繼續(xù)重復(fù)一下上面的操作,發(fā)現(xiàn)第一次的頁面會被緩存,

image

第二次從a前往b,在前往c之后,b一直會被銷毀,無法緩存,有時還會出現(xiàn)沒有銷毀的情況,導(dǎo)致第一次的緩存一直存在,之后每次還是會銷毀b,

image

[圖片上傳中...(image-ac4689-1600762988122-1)]

全都不是我們的菜~!! 通過翻讀vue文檔中的keep-alive的介紹,注意到了它的一個屬性:include,那就換一種寫法,在App.vue中,通過監(jiān)聽路由是否是b到a頁面,來判斷要不要緩存:

 <keep-alive :include="keepAlive">
   <router-view></router-view>
 </keep-alive>
 export default {
   name: "App",
   data() {
     return {
       keepAlive: ['a', 'b']
     }
   },
   watch: {
     $route(to, from) {
     // 如果是從b到a頁面,則不緩存b
       if(from.name === 'b' && to.name === 'a') {
         this.keepAlive = ['a']
       } else {
         this.keepAlive = ['a', 'b']
       }
     }
   }
 }; 

大功告成

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容