keep-alive緩存

設(shè)置緩存不生效的解決方案
  • 1、因為keep-alive組件的include數(shù)組操作的對象是組件名、而不是路由名,因此我們定義每一個路由組件時,都要在組建中顯式聲明name屬性,而不是在路由上聲明name屬性,否則緩存不起作用。而且,一個顯式的name對Vue devtools有提示作用。
  • 2、對于一些vue-element-admin之類的后臺模板中,會存在多層嵌套的router-view,在外層的router-view設(shè)置keep-alive緩存不會對里層router-view中的頁面生效,只有在里層router-view中設(shè)置keep-alive緩存才起作用,如果你設(shè)置了頁面中的name屬性,vue版本也大于2.1,且怎么設(shè)置緩存都不生效的話,不放看看自己頁面布局嵌套的問題,一般都能解決。
以下是正文

在vue官方文檔介紹中,<keep-alive> 包裹動態(tài)組件時,會緩存不活動的組件實例,而不是銷毀它們。我們可以看到在2.1.0版本新增了include和exclude屬性,2.5版本新增了max屬性,屬性的特征如下:
include - 字符串或正則表達式。只有名稱匹配的組件會被緩存。
exclude - 字符串或正則表達式。任何名稱匹配的組件都不會被緩存。
max- 數(shù)字。最多可以緩存多少組件實例。
當組件在 <keep-alive> 內(nèi)被切換,它的 activated 和 deactivated 這兩個生命周期鉤子函數(shù)將會被對應(yīng)執(zhí)行。

keep-alive是個抽象組件(或稱為功能型組件),實際上不會被渲染在DOM樹中。它的作用是在內(nèi)存中緩存組件(不讓組件銷毀),等到下次再渲染的時候,還會保持其中的所有狀態(tài),并且會觸發(fā)activated鉤子函數(shù)。因為緩存的需要通常出現(xiàn)在頁面切換時,所以常與router-view一起出現(xiàn):

如此一來,每一個在router-view中渲染的組件,都會被緩存起來。

如果只想渲染某一些頁面/組件,可以使用keep-alive組件的include/exclude屬性。include屬性表示要緩存的組件名(即組件定義時的name屬性),接收的類型為string、RegExp或string數(shù)組;exclude屬性有著相反的作用,匹配到的組件不會被緩存。假如可能出現(xiàn)在同一router-view的N個頁面中,我只想緩存列表頁和詳情頁,那么可以這樣寫:

<keep-alive :include="['ListView', 'DetailView']">
  <router-view />
</keep-alive>

新增了以上這些api,我們可以叫輕松的實現(xiàn)路由的緩存,假如有以下的使用場景:

  • 現(xiàn)有頁面:首頁(A)、列表頁(B)、詳情頁(C),一般可以從:A->B->C;
  • B到C再返回B時,B要保持原有的狀態(tài);
  • B返回A再進入B時,B不需要保持狀態(tài),是全新的。

很明顯,這個例子中,B是“條件緩存”的,C->B時保持緩存,A->B時放棄緩存。其實解決方案也不難,只需要將B動態(tài)地從include數(shù)組中增加/刪除就行了。具體步驟是:

1、在Vuex中定義一個全局的緩存數(shù)組,待傳給include:

const keepAlive = {
  state: {
    keepAliveRoute: []
  },
  mutations: {
    keepAlive: (state, component) => {
      !state.keepAliveRoute.includes(component) &&
      state.keepAliveRoute.push(component)
    },
    noKeepAlive: (state, component) => {
      const index = state.keepAliveRoute.indexOf(component)
      if (index !== -1) {
        state.keepAliveRoute.splice(index, 1)
      }
    }
  }
}
export default keepAlive

2、在父頁面中定義keep-alive,并傳入全局的緩存數(shù)組:

<template>
  <div style="width:100%;height:100%">
    <keep-alive :include="keepAliveRoute">
      <router-view></router-view>
    </keep-alive>
  </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
  computed: {
    ...mapState({
      keepAliveRoute: state => state.keepAlive.keepAliveRoute
    })
  }
}
</script>

3、緩存:在路由配置頁中,約定使用meta屬性keepAlive,值為true表示組件需要緩存。在全局路由鉤子beforeEach中對該屬性進行處理,這樣一來,每次進入該組件,都進行緩存:

const router = new Router({
  routes: [
    {
      path: '/A/B',
      name: 'B',
      component: B,
      meta: {
        title: 'B頁面',
        keepAlive: true // 這里指定B組件的緩存性
      }
    }
  ]
})

4、在全局路由鉤子beforeEach中添加以下代碼:

router.beforeEach((to, from, next) => {
  // 在路由全局鉤子beforeEach中,根據(jù)keepAlive屬性,統(tǒng)一設(shè)置頁面的緩存性
  // 作用是每次進入該組件,就將它緩存
   if (to.meta.keepAlive) {
    store.commit('keepAlive', to.name)
  }
})

5、取消緩存的時機:對緩存組件使用路由的組件層鉤子beforeRouteLeave。因為B->A->B時不需要緩存B,所以可以認為:當B的下一個頁面不是C時取消B的緩存,那么下次進入B組件時B就是全新的:

beforeRouteLeave (to, from, next) {
    if (to.name !== 'regFormDetail') {
      this.$store.commit('noKeepAlive', from.name)
    }
    next()
  }

因為B的條件緩存,是B自己的職責,所以最好把該業(yè)務(wù)邏輯寫在B的內(nèi)部,而不是A中,這樣不至于讓組件之間的跳轉(zhuǎn)關(guān)系變得混亂。

詳情頁面:

beforeRouteLeave (to, from, next) {
    if (to.name !== 'regFormList' && to.name !== 'regFormSearch') {
      this.$store.commit('noKeepAlive', 'regFormSearch')
    }
    next()
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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