粗淺瞭解keep-alive元件實現原理
阿新 • • 發佈:2018-12-18
首先說明文中大部分思想來自這裡:傳送門,這篇文章只是摘要性整理。
keep-alive元件快取基於VNode節點而不是直接儲存DOM結構。它將滿足條件(include與exclude)的元件在cache物件中快取起來,在需要重新渲染的時候再將vnode節點從cache物件中取出並渲染。
1、DOM虛擬化及銷燬
created鉤子會建立一個cache物件,用來作為快取容器,儲存vnode節點。
created () {
/* 快取物件 */
this.cache = Object.create(null)
},
destroyed鉤子則在元件被銷燬的時候清除cache快取中的所有元件例項。
/* destroyed鉤子中銷燬所有cache中的元件例項 */
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache[key])
}
},
2、元件渲染過程
render函式
render () { /* 得到slot插槽中的第一個元件 */ const vnode: VNode = getFirstComponentChild(this.$slots.default) const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions if (componentOptions) { // check pattern /* 獲取元件名稱,優先獲取元件的name欄位,否則是元件的tag */ const name: ?string = getComponentName(componentOptions) /* name不在inlcude中或者在exlude中則直接返回vnode(沒有取快取) */ if (name && ( (this.include && !matches(this.include, name)) || (this.exclude && matches(this.exclude, name)) )) { return vnode } 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 /* 如果已經做過快取了則直接從快取中獲取元件例項給vnode,還未快取過則進行快取 */ if (this.cache[key]) { vnode.componentInstance = this.cache[key].componentInstance } else { this.cache[key] = vnode } /* keepAlive標記位 */ vnode.data.keepAlive = true } return vnode }
this.cache儲存已快取元件
- 獲取元件name屬性,否則使用tag
- 將name與include和exclude屬性進行匹配,匹配不成功則不進行任何操作直接返回vnode
- 根據key在this.cache中查詢,如果存在則說明之前已經快取過了,直接將快取的vnode的componentInstance(元件例項)覆蓋到目前的vnode上面。否則將vnode儲存在cache中。
if (this.cache[key]) { vnode.componentInstance = this.cache[key].componentInstance } else { this.cache[key] = vnode }
3、修改cache中快取資料
watch 用watch來監聽include與exclude這兩個屬性的改變,在改變的時候修改cache快取中的快取資料。
watch: {
/* 監視include以及exclude,在被修改的時候對cache進行修正 */
include (val: string | RegExp) {
pruneCache(this.cache, this._vnode, name => matches(val, name))
},
exclude (val: string | RegExp) {
pruneCache(this.cache, this._vnode, name => !matches(val, name))
}
},