設(shè)置緩存不生效的解決方案
- 1刊苍、因?yàn)閗eep-alive組件的include數(shù)組操作的對(duì)象是組件名忠荞、而不是路由名曾掂,因此我們定義每一個(gè)路由組件時(shí)聋亡,都要在組建中顯式聲明name屬性绷旗,而不是在路由上聲明name屬性喜鼓,否則緩存不起作用。而且衔肢,一個(gè)顯式的name對(duì)Vue devtools有提示作用庄岖。
- 2、對(duì)于一些vue-element-admin之類的后臺(tái)模板中角骤,會(huì)存在多層嵌套的router-view顿锰,在外層的router-view設(shè)置keep-alive緩存不會(huì)對(duì)里層router-view中的頁(yè)面生效,只有在里層router-view中設(shè)置keep-alive緩存才起作用启搂,如果你設(shè)置了頁(yè)面中的name屬性硼控,vue版本也大于2.1,且怎么設(shè)置緩存都不生效的話胳赌,不放看看自己頁(yè)面布局嵌套的問(wèn)題牢撼,一般都能解決。
以下是正文
在vue官方文檔介紹中疑苫,<keep-alive> 包裹動(dòng)態(tài)組件時(shí)熏版,會(huì)緩存不活動(dòng)的組件實(shí)例,而不是銷毀它們捍掺。我們可以看到在2.1.0版本新增了include和exclude屬性撼短,2.5版本新增了max屬性,屬性的特征如下:
include
- 字符串或正則表達(dá)式挺勿。只有名稱匹配的組件會(huì)被緩存曲横。
exclude
- 字符串或正則表達(dá)式。任何名稱匹配的組件都不會(huì)被緩存不瓶。
max
- 數(shù)字禾嫉。最多可以緩存多少組件實(shí)例。
當(dāng)組件在 <keep-alive> 內(nèi)被切換蚊丐,它的 activated 和 deactivated 這兩個(gè)生命周期鉤子函數(shù)將會(huì)被對(duì)應(yīng)執(zhí)行熙参。
keep-alive是個(gè)抽象組件(或稱為功能型組件),實(shí)際上不會(huì)被渲染在DOM樹中麦备。它的作用是在內(nèi)存中緩存組件(不讓組件銷毀)孽椰,等到下次再渲染的時(shí)候昭娩,還會(huì)保持其中的所有狀態(tài),并且會(huì)觸發(fā)activated鉤子函數(shù)黍匾。因?yàn)榫彺娴男枰ǔ3霈F(xiàn)在頁(yè)面切換時(shí)栏渺,所以常與router-view一起出現(xiàn):
如此一來(lái),每一個(gè)在router-view中渲染的組件膀捷,都會(huì)被緩存起來(lái)迈嘹。
如果只想渲染某一些頁(yè)面/組件削彬,可以使用keep-alive組件的include/exclude屬性全庸。include屬性表示要緩存的組件名(即組件定義時(shí)的name屬性),接收的類型為string融痛、RegExp或string數(shù)組壶笼;exclude屬性有著相反的作用,匹配到的組件不會(huì)被緩存雁刷。假如可能出現(xiàn)在同一router-view的N個(gè)頁(yè)面中覆劈,我只想緩存列表頁(yè)和詳情頁(yè),那么可以這樣寫:
<keep-alive :include="['ListView', 'DetailView']">
<router-view />
</keep-alive>
新增了以上這些api沛励,我們可以叫輕松的實(shí)現(xiàn)路由的緩存责语,假如有以下的使用場(chǎng)景:
- 現(xiàn)有頁(yè)面:首頁(yè)(A)、列表頁(yè)(B)目派、詳情頁(yè)(C)坤候,一般可以從:A->B->C;
- B到C再返回B時(shí)企蹭,B要保持原有的狀態(tài)白筹;
- B返回A再進(jìn)入B時(shí),B不需要保持狀態(tài)谅摄,是全新的徒河。
很明顯,這個(gè)例子中送漠,B是“條件緩存”的顽照,C->B時(shí)保持緩存,A->B時(shí)放棄緩存闽寡。其實(shí)解決方案也不難棒厘,只需要將B動(dòng)態(tài)地從include數(shù)組中增加/刪除就行了。具體步驟是:
1下隧、在Vuex中定義一個(gè)全局的緩存數(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、在父頁(yè)面中定義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何乎、緩存:在路由配置頁(yè)中句惯,約定使用meta屬性keepAlive,值為true表示組件需要緩存支救。在全局路由鉤子beforeEach中對(duì)該屬性進(jìn)行處理抢野,這樣一來(lái),每次進(jìn)入該組件各墨,都進(jìn)行緩存:
const router = new Router({
routes: [
{
path: '/A/B',
name: 'B',
component: B,
meta: {
title: 'B頁(yè)面',
keepAlive: true // 這里指定B組件的緩存性
}
}
]
})
4指孤、在全局路由鉤子beforeEach中添加以下代碼:
router.beforeEach((to, from, next) => {
// 在路由全局鉤子beforeEach中,根據(jù)keepAlive屬性贬堵,統(tǒng)一設(shè)置頁(yè)面的緩存性
// 作用是每次進(jìn)入該組件恃轩,就將它緩存
if (to.meta.keepAlive) {
store.commit('keepAlive', to.name)
}
})
5、取消緩存的時(shí)機(jī):對(duì)緩存組件使用路由的組件層鉤子beforeRouteLeave黎做。因?yàn)锽->A->B時(shí)不需要緩存B叉跛,所以可以認(rèn)為:當(dāng)B的下一個(gè)頁(yè)面不是C時(shí)取消B的緩存,那么下次進(jìn)入B組件時(shí)B就是全新的:
beforeRouteLeave (to, from, next) {
if (to.name !== 'regFormDetail') {
this.$store.commit('noKeepAlive', from.name)
}
next()
}
因?yàn)锽的條件緩存蒸殿,是B自己的職責(zé)筷厘,所以最好把該業(yè)務(wù)邏輯寫在B的內(nèi)部,而不是A中宏所,這樣不至于讓組件之間的跳轉(zhuǎn)關(guān)系變得混亂酥艳。
詳情頁(yè)面:
beforeRouteLeave (to, from, next) {
if (to.name !== 'regFormList' && to.name !== 'regFormSearch') {
this.$store.commit('noKeepAlive', 'regFormSearch')
}
next()
}