vue的另一個內建元件keep-alive
keep-alive是vue提供的用來快取元件的,被keep-alive包裹的元件在離開時不會銷燬要離開的元件,而是將其快取在記憶體中,避免重新渲染,,需要注意的是keep-alive是vue2.0及以上版本具有的,2.0以下版本不具有該元件。
用這個虛擬元件對我得網站有什麼好處?
回想一下你實際開發網站的時候是否又這樣的場景,頁面上有幾個tab頁來回切換展示不同的資料,如果沒有,那網頁導航肯定會有吧?沒有tab頁切換總有導航切換吧~~,在切換的過程中(特別是tab切換),每切換到一個頁面就會完全重新渲染一次,元件裡的data,comouted等等要重新計算,包括頁面上的資料都要重新請求,如果資料多的話每次切換都能明顯的感覺到‘閃白屏’,這樣使用者體驗很不好,而且造成很多不必要的請求,如果平時有考慮過網站效能問題,那你肯定聽過‘要想大幅度優化頁面,必須從http請求上入手’,這個時候就要用keep-alive了,用了後你會發現只有第一次切換的時候需要請求資料,渲染元件,第二次再切換的時候就直接拿快取了。
檢視效果:
recommend.vue頁面新增鉤子函式列印
第一次切換到動態tab頁,請求資料
第二次切換到動態tab頁,沒有任何請求
兩次切換控制檯列印,沒有走destroyed函式銷燬元件,兩次切換隻有第一次列印建立元件和掛載,第二次拿的快取
怎麼用?
具體用法請百度吧,很全啊!!:laughing:
快取究竟在哪裡?
在元件裡列印this,層層遞進的尋找,最終找到,具體路徑是:VueComponent>$vnode(虛擬DOM)>parent(這一級找到的是keep-alive)>componentInstance(元件例項)>cache
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:
按照路徑找到的cache
幾個注意點
大體思路應該理解了,說一下我用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回撥函式裡處理
——————————————————————————————————————————————————————————————————————————————