Vue 全站緩存之 keep-alive : 動態移除緩存

閱讀本文以前,默認你們對 vue 和 keep-alive 都很熟悉,因此再也不囉嗦相關資料,直接進入正文。

有耐心的話,且聽我細細道來,若是你遇到過相似問題,或正在尋找解決方案,那麼你能夠直接翻到文末看結論。javascript

前言

以一個記帳項目舉例,常見的場景有首頁、記到帳頁面、選擇合同、新建合同、選擇客戶、新建客戶這些頁面。html

clipboard.png

在這些頁面中,很顯然,用戶的瀏覽行爲應該是逐漸深刻的,通俗得講就是瀏覽頁面在不斷前進。vue

並且這些頁面之間仍是有互動性存在的,兩種互動行爲:java

  • 一. 用戶前進時,老是進入新的頁面。(好比在合同列表頁反覆加載屢次列表以後,進入其中一個合同詳情,再返回時,應該仍停留以前裏列表頁同一個位置,而不是從新刷新列表頁。)
  • 二. 用戶後退時,須要能保留前一頁數據並繼續操做。(好比,記到帳時須要選擇合同,選擇合同時能夠新建合同,新建合同時填了一堆數據能夠去選擇客戶,在選擇客戶時又去建立了客戶,那麼這一堆操做下來應該可以作到:建立完客戶後繼續新建合同,建完合同後繼續記該合同的到帳

clipboard.png

上圖是 demo 項目中的真實效果,目前常見的 vue 開發方案裏,通常都會引入 vuex 或 localStorage ,在各個頁面不斷的存儲和調用頁面內的數據,我以爲,這很不科學很不優雅node

keep-alive 什麼問題

vue 支持 keep-alive 組件,若是啓用,頁面內的全部數據都會被保留,因此,上文的互動行爲二後退時保留前一頁數據繼續操做沒有問題。git

問題出在互動行爲一用戶前進時老是進入新頁面,然而一旦緩存,你就無法老是進新頁面了,你老是進入緩存頁,這就很讓人頭疼了。github

官方提供了includeexclude特性,說你能夠決定哪些頁面使用緩存哪些頁面不用緩存。連接vue-router

然而問題又回到了原點,並無解決咱們酌情決定是否使用已緩存的緩存這一需求。vuex

因此不少人想到了一個方法在離開頁面時銷燬這個頁面是否是就能夠了,然而並不能,這裏出現了 bug ,組件銷燬了緩存還在:
clipboard.pngapi

因而,就有人提出但願keep-alive能增長能夠動態刪除已緩存組件的功能issue

這是個老話題,以前一直沒有進展,核心緣由就在於 keep-alive 不能正確處理已銷燬的組件。

嘗試解決這個問題

若是能實現動態使用緩存這一功能,那麼全部問題也就迎刃而解。

最初,我研究 keep-alive 的代碼,發現了這麼一段代碼:

clipboard.png

因而,我想,若是在此處判斷若是組件已被銷燬則不使用緩存,是否是就解決這個問題了,因而我提交了一個 PR:

clipboard.png

不過這個 PR 遲遲沒有經過,我就放棄了。

暴力解決這個問題

我繼續研究有沒有其餘方案,而後我在打印組件變量的時候,發現了這麼個眼熟的字段:

clipboard.png

這不就是 keep-alive 的組件嘛,我趕緊點開再看,發現了更眼熟的東東:

clipboard.png

因而,這事兒就變得簡單了,直接按圖索驥,咱在銷燬組件以前,尋找路由組件所在父級的 keep-alive 組件,操控其中的 cache 列表,強行刪除其中的緩存,問題也就迎刃而解,是否是很直接很暴力。

結論

keep-alive 默認不支持動態銷燬已緩存的組件,因此此處給出的解決方案是經過直接操控 keep-alvie 組件裏的 cahce 列表,暴力移除緩存:

//使用Vue.mixin的方法攔截了路由離開事件,並在該攔截方法中實現了銷燬頁面緩存的功能。
Vue.mixin({
    beforeRouteLeave:function(to, from, next){
        if (from && from.meta.rank && to.meta.rank && from.meta.rank>to.meta.rank)
        {//此處判斷是若是返回上一層,你能夠根據本身的業務更改此處的判斷邏輯,酌情決定是否摧毀本層緩存。
            if (this.$vnode && this.$vnode.data.keepAlive)
            {
                if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache)
                {
                    if (this.$vnode.componentOptions)
                    {
                        var key = this.$vnode.key == null
                                    ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
                                    : this.$vnode.key;
                        var cache = this.$vnode.parent.componentInstance.cache;
                        var keys  = this.$vnode.parent.componentInstance.keys;
                        if (cache[key])
                        {
                            if (keys.length) {
                                var index = keys.indexOf(key);
                                if (index > -1) {
                                    keys.splice(index, 1);
                                }
                            }
                            delete cache[key];
                        }
                    }
                }
            }
            this.$destroy();
        }
        next();
    },
});

後語

本文主要圍繞如何動態刪除 keep-alive 緩存這一問題進行探索,其餘關於如何設定頁面層級、如何在先後頁之間進行數據傳遞等問題,敬請期待《Vue 全站緩存之 vue-router-then :先後頁數據傳遞》。

請繼續閱讀-系列篇2:Vue 全站緩存二:如何設計全站緩存

原文來自阿星的博客:http://wanyaxing.com/blog/201...

相關文章
相關標籤/搜索