vue的另一個內建元件keep-alive

南風知我意NY發表於2019-04-13

vue的另一個內建元件keep-alive

keep-alive是vue提供的用來快取元件的,被keep-alive包裹的元件在離開時不會銷燬要離開的元件,而是將其快取在記憶體中,避免重新渲染,,需要注意的是keep-alive是vue2.0及以上版本具有的,2.0以下版本不具有該元件。

用這個虛擬元件對我得網站有什麼好處?

回想一下你實際開發網站的時候是否又這樣的場景,頁面上有幾個tab頁來回切換展示不同的資料,如果沒有,那網頁導航肯定會有吧?沒有tab頁切換總有導航切換吧~~,在切換的過程中(特別是tab切換),每切換到一個頁面就會完全重新渲染一次,元件裡的data,comouted等等要重新計算,包括頁面上的資料都要重新請求,如果資料多的話每次切換都能明顯的感覺到‘閃白屏’,這樣使用者體驗很不好,而且造成很多不必要的請求,如果平時有考慮過網站效能問題,那你肯定聽過‘要想大幅度優化頁面,必須從http請求上入手’,這個時候就要用keep-alive了,用了後你會發現只有第一次切換的時候需要請求資料,渲染元件,第二次再切換的時候就直接拿快取了。

檢視效果:

recommend.vue頁面新增鉤子函式列印

vue的另一個內建元件keep-alive

第一次切換到動態tab頁,請求資料

vue的另一個內建元件keep-alive

第二次切換到動態tab頁,沒有任何請求

vue的另一個內建元件keep-alive

兩次切換控制檯列印,沒有走destroyed函式銷燬元件,兩次切換隻有第一次列印建立元件和掛載,第二次拿的快取

vue的另一個內建元件keep-alive

怎麼用?

具體用法請百度吧,很全啊!!:laughing:

快取究竟在哪裡?

在元件裡列印this,層層遞進的尋找,最終找到,具體路徑是:VueComponent>$vnode(虛擬DOM)>parent(這一級找到的是keep-alive)>componentInstance(元件例項)>cache

vue的另一個內建元件keep-alive

cache是一個Object,每個key對應一個元件的快取,開啟cache下的componentInstance(元件例項),你會發現和VueComponent > $vnode > componentInstance 一樣,他的快取,當然得和他一樣了~

怎麼實現的快取?

簡單看一下原始碼吧 rander函式:

keep-alive也是一個元件,也符合元件的基本構造,有prop,mounted,created等,但是主要的就是他的rander函式了,即渲染規則
render () {
	<!-- 在keep-alive元件檔案裡,this指向當前元件例項,即上文提到的層層遞進找到的parent.componentInstance -->

	<!-- 按照this.$slot.default找,發現default是一個陣列,存的是一個vnode,這個vnode就是用keep-alive包裹的當前要渲染的元件,如下圖所示-->
    const slot = this.$slots.default

    <!--將default[0]賦值給vnode常量  -->
    const vnode: VNode = getFirstComponentChild(slot) 

    <!-- 將vnode.componentOptions賦值給componentOptions -->
    const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions

    <!-- 不必細究---開始 -->
    if (componentOptions) {
      const name: ?string = getComponentName(componentOptions)
      const { include, exclude } = this
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }
      <!-- 不必細究--結束 -->

	<!-- 重點 -->
	<!-- 將this.cache和this.keys(this指向上文已說明)賦值給常量cahce和key -->
      const { cache, keys } = this  

    <!-- 判斷vnode.key存在嗎,不存在就賦值常量key為componentOptions.Ctor.cid,存在就賦值常量key為vnode.key,拿到的key為要渲染的元件對應的key值,我拿到的是94-->
      const key: ?string = vnode.key == null
        ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
        : vnode.key

    <!--再看cache是個物件,如下圖,key值為94對應一個vnode,找到了,說明有快取  -->
      if (cache[key]) {
      	<!-- 有快取當然是要拿快取了,將快取裡的元件例項賦值給即將渲染的元件的例項 -->
        vnode.componentInstance = cache[key].componentInstance
        remove(keys, key)
        keys.push(key)
      } else {
        cache[key] = vnode
        keys.push(key)
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
      }

      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
}
複製程式碼

按照路徑找到的default:

vue的另一個內建元件keep-alive

按照路徑找到的cache

vue的另一個內建元件keep-alive

幾個注意點

大體思路應該理解了,說一下我用keep-alive的時候踩過的幾個坑:

  • 版本問題,文字開頭就提到了,keep-alive是vue2.0以上的版本才具有的,而且vue2.1+的版本才支援有條件的快取,也就是include和exculed兩個屬性,用之前請先開啟專案的package.json檢視vue的版本
  • name值的問題,include和exclude屬性裡寫的是元件的name值,注意是元件.vue檔案裡的name值,export default{}裡的元件的name值,並不是路由檔案裡的name值
  • 多級子路由的問題,keep-alive包裹著誰,就會快取誰,並不會快取子路由對應的元件,如果你想快取子路由的元件,那就需要給子路由對應的router-view也包裹上keep-alive。
  • keep-alive快取的元件如果渲染時拿的是快取,那麼,元件data、computed裡的屬性都不會重新計算,完全是拿的第一次渲染時的值,所以,如果有改變的話可以再activated回撥函式裡處理

——————————————————————————————————————————————————————————————————————————————

以上僅為個人用keep-alive的總結,如有問題歡迎指出!

相關文章