詳解Vue適時清理keepalive緩存方案
需求
單頁面應用中,用戶進入表單填寫頁面,需要初始化表單內容,填寫過程中可能涉及到地圖選點或者列表選擇等操作,需要到新的頁面選擇並回調顯示。
此時我們需要緩存表單填寫頁面實例,當退出表單填寫或提交完表單內容之後,需要銷毀當前表單實例,下次進入重新進行初始化
思考
說到 Vue
緩存,我們肯定首先選擇官方提供的緩存方案 keep-alive
內置組件來實現。
keep-alive
組件提供給我們緩存組件的能力,可以完整的保存當前組件的狀態,這幫瞭我們很大的忙
但實際業務場景中,我們很多時候是按需緩存頁面的,就像 App
開發那樣,每個頁面都是單獨的一個頁面實例,由於 Vue Router
的限制,每個頁面有固定的一個 path
,所以導致每次訪問這個 path
都會命中同一個組件實例
這個時候可能會有小夥伴說
誒,不是可以用
activated
來進行頁面更新或者處理嗎?
沒錯,是可以這樣,但是,有些操作是 mounted
裡面要做,有些需要放到 activated
裡面更新,代碼要處理很多進入頁面的操作,就很麻煩啊。
此時就有兩個思考方向:
- 在必要的時候清除掉緩存頁面的實例
- 每次 push 頁面的時候,保證當前頁面是全新的實例對象,和
App
頁面棧相同
第二種方案可以比較物理的解決需求中的問題,但是需要改動的地方很多,比如 Vue Router
中路由切換的時候,是否采用動態生成 path
,確保當前頁面實例不唯一,而且我們也要做好自己的頁面棧管理,類似於 iOS
中的 UINavigationController
,以便於及時清理棧中緩存的頁面實例
因為改動比較大,而且需要大量測試,所以最後還是選擇在方案一的方向進行探索和嘗試。
嘗試
1. 手動操作 keep-alive 組件的 cache 數組
// 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; }
通過路由守衛在特定的情況下刪除 cache
數組中的頁面實例,同時 destory
當前實例
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
數組,可能會產生一些預期外的泄漏問題或者運行問題,雖然我自己嘗試的時候沒有發現。。
在 Vue 3
中我也嘗試去尋找對應的 cache
數組,還真被我找到瞭,但是 Vue 3
源碼中對於 cache
數組的操作權限僅限於開發環境
// Vue 3 KeepAlive 組件片段 if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { ;(instance as any).__v_cache = cache }
部署生產環境之後就沒辦法通過 instance.__v_cache
來獲取 cache
數組瞭,所以這種方案到 Vue 3 就沒辦法進行下去啦。
於是乎,就有瞭第二個嘗試
2. exclude 大法好
之前接觸 keep-alive
所有註意力都放在 include
這個屬性上面,其實 exclude
屬性同樣重要,而且效果和我們直接刪除 cache
數組異曲同工。
// Vue 3 KeepAlive 組件片段 if ( (include && (!name || !matches(include, name))) || (exclude && name && matches(exclude, name)) ) { current = vnode return rawVNode }
如果 exclude
裡面有值,那麼就返回當前新的實例不從 cache
裡面獲取。而且 exclude
的優先級是高於 include
的。
利用這一點,我們就可以通過操作 exclude
中的內容,來達到控制緩存頁面的效果。
而且 exclude
在 Vue 3
中的控制更為方便,隻需要定義一個全局的 exclude
響應式變量就可以隨處操作瞭,清除的具體方式取決於業務流程
export const excludes = ref<string[]>([]); // 需要刪除的時候 export function removeKeepAliveCache(name: string) { excludes.value.push(name); } // 需要恢復緩存的時候 export function resetKeepAliveCache(name: string) { excludes.value = excludes.value.filter((item) => item !== name); }
Demo
這裡提供一個小 demo 演示一下緩存清除效果:
https://ztstory.github.io/vue-composition-demo/#/
流程:
-
Index
與Input
為緩存頁面 -
Input
返回到Index
時清除Input
緩存,重新進入Input
頁面激活緩存
Demo 源碼地址:https://github.com/ZTStory/vue-composition-demo
到此這篇關於詳解Vue適時清理keepalive緩存方案的文章就介紹到這瞭,更多相關Vue清理keepalive緩存內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 如何管理Vue中的緩存頁面
- vue使用keep-alive後清除緩存的方法
- LRU算法在Vue內置組件keep-alive中的使用
- vue中使用keep-alive動態刪除已緩存組件方式
- 圖文詳解keep-alive如何清除緩存