Use keep-alive component vue its implementation principle

Vue.js keep-alive is a built-in component. It is able to inactive component instance stored in memory, rather than directly to its destruction, it is an abstract component will not be rendered to the real DOM, it will not appear in the chain of parent components.

It provides two attributes include and exclude, allowing conditional assembly cache.

Specific content can refer to the official website .

use

usage

<keep-alive>
    <component></component>
</keep-alive>

Here's component assemblies are cached.

For chestnuts

<keep-alive>
    <coma v-if="test"></coma>
    <comb v-else="test"></comb>
</keep-alive>
<button @click="test=handleClick">请点击</button>
export default {
    data () {
        return {
            test: true
        }
    },
    methods: {
        handleClick () {
            this.test = !this.test;
        }
    }
}

Click the button in time, coma and comb two components switch will happen, but this time the status of these two components will be cached, such as coma and comb assembly has an input label, then input the content label does not because of the switch assembly and disappear.

props

keep-alive component provides two attributes to include and exclude conditionally allow assembly cache, both strings may be separated by a comma, or a regular expression to represent the array.

<keep-alive include="a">
  <component></component>
</keep-alive>

The name of a buffer component.

<keep-alive exclude="a">
  <component></component>
</keep-alive>

a name of the component will not be cached.

Life hooks

keep-alive life provides two hooks, which are activated and deactivated.

Because keep-alive components will be stored in memory and will not be destroyed and re-created, so it will not re-created components such as calling the method, activated and deactivated with the needs of these two lives hook to know the current component is active.


Depth keep-alive component implementation

Having the use of keep-alive components, we look at from the perspective of the source component keep-alive Cache exactly how the components of it?
created and destroyed hook

created hook create a cache object that is used as a cache container, save vnode node.

created () {
    /* 缓存对象 */
    this.cache = Object.create(null)
},

destroyed the hook component instances clear all cache cache when the component is destroyed.

/* destroyed钩子中销毁所有cache中的组件实例 */
destroyed () {
    for (const key in this.cache) {
        pruneCacheEntry(this.cache[key])
    }
},

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
}

First get the first child component through getFirstComponentChild, get name of the component (the presence of the component name component name is used directly, otherwise it will use the tag). This will be followed by a name and include exclude property, the matching is unsuccessful (no need for cache instructions) nothing is done directly returned vnode, vnode is an object of a type VNode, students can understand VNode refer to the author of another article "VNode node" .

/* 检测name是否匹配 */
function matches (pattern: string | RegExp, name: string): boolean {
  if (typeof pattern === 'string') {
    /* 字符串情况,如a,b,c */
    return pattern.split(',').indexOf(name) > -1
  } else if (isRegExp(pattern)) {
    /* 正则 */
    return pattern.test(name)
  }
  /* istanbul ignore next */
  return false
}

Functions include detecting and exclude property matching is simple, include and exclude attributes, such as to support a string "a, b, c" in this case of the component name and a comma-separated regular expressions. It matches the current detect match component of these ways.

if (this.cache[key]) {
    vnode.componentInstance = this.cache[key].componentInstance
} else {
    this.cache[key] = vnode
}

The next thing is very simple, look at this.cache according to the key, if there is then the previously cached, and direct the vnode cache of componentInstance (component instance) to cover the current vnode above. Otherwise vnode is stored in the cache.

Finally returned vnode (which has been replaced with a vnode componentInstance into the cache when the cache).

watch

A watch to monitor changes in these two properties include and exclude, modifying cached data cache cache in time for a change.

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

PruneCache achieve the look.

/* 修正cache */
function pruneCache (cache: VNodeCache, current: VNode, filter: Function) {
  for (const key in cache) {
    /* 取出cache中的vnode */
    const cachedNode: ?VNode = cache[key]
    if (cachedNode) {
      const name: ?string = getComponentName(cachedNode.componentOptions)
      /* name不符合filter条件的,同时不是目前渲染的vnode时,销毁vnode对应的组件实例(Vue实例),并从cache中移除 */
      if (name && !filter(name)) {
        if (cachedNode !== current) {
          pruneCacheEntry(cachedNode)
        }
        cache[key] = null
      }
    }
  }
} 

/* 销毁vnode对应的组件实例(Vue实例) */
function pruneCacheEntry (vnode: ?VNode) {
  if (vnode) {
    vnode.componentInstance.$destroy()
  }
}

Through all the items in the cache, if you do not meet the filter specified rules, it will be executed pruneCacheEntry. pruneCacheEntry component instance will call $ destroy method to destroy components.


At last

The internal Vue.js abstraction into a DOM node th VNode node , keep-alive cache component based VNode node is not directly stored in the DOM structure. It satisfies the condition (include with the exclude) components cached in the cache object, and then taken out and re rendered when rendering a node vnode from the object cache.

Original: talk about the use of keep-alive component and its implementation principle

Reproduced in: https: //www.jianshu.com/p/f3c52707656a

Guess you like

Origin blog.csdn.net/weixin_34408717/article/details/91295211