詳解Vue適時(shí)清理keepalive緩存方案
需求
單頁(yè)面應(yīng)用中,用戶進(jìn)入表單填寫頁(yè)面,需要初始化表單內(nèi)容,填寫過程中可能涉及到地圖選點(diǎn)或者列表選擇等操作,需要到新的頁(yè)面選擇并回調(diào)顯示。
此時(shí)我們需要緩存表單填寫頁(yè)面實(shí)例,當(dāng)退出表單填寫或提交完表單內(nèi)容之后,需要銷毀當(dāng)前表單實(shí)例,下次進(jìn)入重新進(jìn)行初始化
思考
說(shuō)到 Vue
緩存,我們肯定首先選擇官方提供的緩存方案 keep-alive
內(nèi)置組件來(lái)實(shí)現(xiàn)。
keep-alive
組件提供給我們緩存組件的能力,可以完整的保存當(dāng)前組件的狀態(tài),這幫了我們很大的忙
但實(shí)際業(yè)務(wù)場(chǎng)景中,我們很多時(shí)候是按需緩存頁(yè)面的,就像 App
開發(fā)那樣,每個(gè)頁(yè)面都是單獨(dú)的一個(gè)頁(yè)面實(shí)例,由于 Vue Router
的限制,每個(gè)頁(yè)面有固定的一個(gè) path
,所以導(dǎo)致每次訪問這個(gè) path
都會(huì)命中同一個(gè)組件實(shí)例
這個(gè)時(shí)候可能會(huì)有小伙伴說(shuō)
誒,不是可以用
activated
來(lái)進(jìn)行頁(yè)面更新或者處理嗎?
沒錯(cuò),是可以這樣,但是,有些操作是 mounted
里面要做,有些需要放到 activated
里面更新,代碼要處理很多進(jìn)入頁(yè)面的操作,就很麻煩啊。
此時(shí)就有兩個(gè)思考方向:
- 在必要的時(shí)候清除掉緩存頁(yè)面的實(shí)例
- 每次 push 頁(yè)面的時(shí)候,保證當(dāng)前頁(yè)面是全新的實(shí)例對(duì)象,和
App
頁(yè)面棧相同
第二種方案可以比較物理的解決需求中的問題,但是需要改動(dòng)的地方很多,比如 Vue Router
中路由切換的時(shí)候,是否采用動(dòng)態(tài)生成 path
,確保當(dāng)前頁(yè)面實(shí)例不唯一,而且我們也要做好自己的頁(yè)面棧管理,類似于 iOS
中的 UINavigationController
,以便于及時(shí)清理?xiàng)V芯彺娴捻?yè)面實(shí)例
因?yàn)楦膭?dòng)比較大,而且需要大量測(cè)試,所以最后還是選擇在方案一的方向進(jìn)行探索和嘗試。
嘗試
1. 手動(dòng)操作 keep-alive 組件的 cache 數(shù)組
// Vue 2 keep-alive 部分源碼片段 const { cache, keys } = this; const key: ?string = vnode.key == null ? // same constructor may get registered as different local components // so cid alone is not enough (#3269) componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : "") : vnode.key; if (cache[key]) { vnode.componentInstance = cache[key].componentInstance; // make current key freshest remove(keys, key); keys.push(key); } else { // delay setting the cache until update this.vnodeToCache = vnode; this.keyToCache = key; }
通過路由守衛(wèi)在特定的情況下刪除 cache
數(shù)組中的頁(yè)面實(shí)例,同時(shí) destory
當(dāng)前實(shí)例
removeKeepAliveCacheForVueInstance(vueInstance) { let key = vueInstance.$vnode.key ?? vueInstance.$vnode.componentOptions.Ctor.cid + (vueInstance.$vnode.componentOptions.tag ? `::${vueInstance.$vnode.componentOptions.tag}` : ""); let cache = vueInstance.$vnode.parent.componentInstance.cache; let keys = vueInstance.$vnode.parent.componentInstance.keys; if (cache[key]) { vueInstance.$destroy(); delete cache[key]; let index = keys.indexOf(key); if (index > -1) { keys.splice(index, 1); } } }
這種方案比較繁瑣,但由于是直接操作 cache
數(shù)組,可能會(huì)產(chǎn)生一些預(yù)期外的泄漏問題或者運(yùn)行問題,雖然我自己嘗試的時(shí)候沒有發(fā)現(xiàn)。。
在 Vue 3
中我也嘗試去尋找對(duì)應(yīng)的 cache
數(shù)組,還真被我找到了,但是 Vue 3
源碼中對(duì)于 cache
數(shù)組的操作權(quán)限僅限于開發(fā)環(huán)境
// Vue 3 KeepAlive 組件片段 if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { ;(instance as any).__v_cache = cache }
部署生產(chǎn)環(huán)境之后就沒辦法通過 instance.__v_cache
來(lái)獲取 cache
數(shù)組了,所以這種方案到 Vue 3 就沒辦法進(jìn)行下去啦。
于是乎,就有了第二個(gè)嘗試
2. exclude 大法好
之前接觸 keep-alive
所有注意力都放在 include
這個(gè)屬性上面,其實(shí) exclude
屬性同樣重要,而且效果和我們直接刪除 cache
數(shù)組異曲同工。
// Vue 3 KeepAlive 組件片段 if ( (include && (!name || !matches(include, name))) || (exclude && name && matches(exclude, name)) ) { current = vnode return rawVNode }
如果 exclude
里面有值,那么就返回當(dāng)前新的實(shí)例不從 cache
里面獲取。而且 exclude
的優(yōu)先級(jí)是高于 include
的。
利用這一點(diǎn),我們就可以通過操作 exclude
中的內(nèi)容,來(lái)達(dá)到控制緩存頁(yè)面的效果。
而且 exclude
在 Vue 3
中的控制更為方便,只需要定義一個(gè)全局的 exclude
響應(yīng)式變量就可以隨處操作了,清除的具體方式取決于業(yè)務(wù)流程
export const excludes = ref<string[]>([]); // 需要?jiǎng)h除的時(shí)候 export function removeKeepAliveCache(name: string) { excludes.value.push(name); } // 需要恢復(fù)緩存的時(shí)候 export function resetKeepAliveCache(name: string) { excludes.value = excludes.value.filter((item) => item !== name); }
Demo
這里提供一個(gè)小 demo 演示一下緩存清除效果:
https://ztstory.github.io/vue-composition-demo/#/
流程:
Index
與Input
為緩存頁(yè)面Input
返回到Index
時(shí)清除Input
緩存,重新進(jìn)入Input
頁(yè)面激活緩存
Demo 源碼地址:https://github.com/ZTStory/vue-composition-demo
到此這篇關(guān)于詳解Vue適時(shí)清理keepalive緩存方案的文章就介紹到這了,更多相關(guān)Vue清理keepalive緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3實(shí)現(xiàn)一個(gè)可左右滑動(dòng)操作組件的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Vue3實(shí)現(xiàn)一個(gè)可左右滑動(dòng)操作組件,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Vue有一定幫助,感興趣的可以學(xué)一下2022-11-11element-ui 遠(yuǎn)程搜索組件el-select在項(xiàng)目中組件化的實(shí)現(xiàn)代碼
這篇文章主要介紹了element-ui 遠(yuǎn)程搜索組件el-select在項(xiàng)目中組件化,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12vue實(shí)現(xiàn)在進(jìn)行增刪改操作后刷新頁(yè)面
這篇文章主要介紹了vue實(shí)現(xiàn)在進(jìn)行增刪改操作后刷新頁(yè)面,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-08-08vue中mock數(shù)據(jù),模擬后臺(tái)接口實(shí)例
這篇文章主要介紹了vue中mock數(shù)據(jù),模擬后臺(tái)接口實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04vue3+Typescript實(shí)現(xiàn)路由標(biāo)簽頁(yè)和面包屑功能
在使用 Vue.js 開發(fā)后臺(tái)管理系統(tǒng)時(shí),經(jīng)常會(huì)遇到需要使用路由標(biāo)簽頁(yè)的場(chǎng)景,這篇文章主要介紹了vue3+Typescript實(shí)現(xiàn)路由標(biāo)簽頁(yè)和面包屑,需要的朋友可以參考下2023-05-05VUE2響應(yīng)式原理使用Object.defineProperty缺點(diǎn)
這篇文章主要為大家介紹了VUE2響應(yīng)式原理使用Object.defineProperty缺點(diǎn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08SpringBoot+Vue前后端分離,使用SpringSecurity完美處理權(quán)限問題的解決方法
這篇文章主要介紹了SpringBoot+Vue前后端分離,使用SpringSecurity完美處理權(quán)限問題,需要的朋友可以參考下2018-01-01Vue3+Koa2實(shí)現(xiàn)圖片上傳功能的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何使用Vue3和Koa2實(shí)現(xiàn)圖片上傳功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02