vue keep-alive组件的运用以及道理。

keep-alive

keep-alive是vue.js的内置组件,它可以把不运动的组件的实例保留在内存中,而不是直接的烧毁,它是一个笼统组件,不会被衬着到实在DOM中,也不会出现在父组件链中。
它供应了exclude和include两个属性,许可组件有前提的缓存。

运用

<keep-alive>
    <comment></comment>
</keep-alive>

上面的comment组件会被缓存起来。

<keep-alive>
    <coma v-if="test"></coma>
    <comb v-else></comb>
</keep-alive>
<button @click="abc"></button>

export default{
    data(){
        reurn{
            test:true
        }
    },
    methods:{
        abc(){
            this.test=!this.test;
        }
    }
}

点击button的时刻coma组件和comb组件会发作切换,但这时候刻两个组件的状况会被缓存起来,假如说a和b组件中都有一个input标签,这时候切换input标签的值不会转变。

props

keep-alive组件供应了include和exclude两个属性来举行有前提的缓存,两者都可以用逗号分开字符串、正则表达式或则数组示意。

<keep-alive include="a">
    <component></component>
</keep-alive>
//name名为a的组件会被缓存起来

<keep-alive exclude="a">
    <component></component>
</keep-alive>
//name名为a的组件将不会被缓存。

性命钩子

keep-alive供应了两个性命钩子,actived与deactived。
由于keep-alive会把组件保留到内存中,并不会烧毁或则从新构建,所以不会挪用组件的creted等要领,须要运用actived和deactived两个钩子推断组件是不是处于运动状况。

深切keep-alive组件的完成

created和destroyed钩子
created钩子会建立一个cache对象,用来作为缓存容器,保留Vnode节点。

created{
    this.cache=Object.create(null);
}

destroyed钩子则在组件烧毁的时刻消灭cache缓存中的一切组件实例。

/* 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
}

起首经由过程getFirstComponentChild猎取第一个子组件,猎取该组件的name(存在组件名则直接运用组件名,不然会运用tag)。接下来会将这个name经由过程include与exclude属性举行婚配,婚配不成功(申明不须要举行缓存)则不举行任何操纵直接返回vnode。

/* 检测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
}

检测include与exclude属性婚配的函数很简单,include与exclude属性支撑字符串如”a,b,c”如许组件名以逗号离隔的状况以及正则表达式。matches经由过程这两种体式格局离别检测是不是婚配当前组件。

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

接下来的事变很简单,依据key在this.cache中查找,假如存在则申明之前已缓存过了,直接将缓存的vnode的componentInstance(组件实例)掩盖到现在的vnode上面。不然将vnode存储在cache中。
末了返回vnode(有缓存时该vnode的componentInstance已被替换成缓存中的了)。
用watch来监听pruneCache与pruneCache这两个属性的转变,在转变的时刻修改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))
    }
},

来看一下pruneCache的完成。

/* 修改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()
  }
}
遍历cache中的一切项,假如不符合filter指定的划定规矩的话,则会实行pruneCacheEntry。pruneCacheEntry则会挪用组件实例的$destroy要领来将组件烧毁。
    原文作者:Lessong
    原文地址: https://segmentfault.com/a/1190000018705351
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞