1. 程式人生 > >粗淺瞭解keep-alive元件實現原理

粗淺瞭解keep-alive元件實現原理

首先說明文中大部分思想來自這裡:傳送門,這篇文章只是摘要性整理。

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))
    }
},