vue keep-alive组件

keep-alive

<keep-alive>是一个vue的内置组件,会缓存不活动的组件实例,他自身不会渲染一个DOM元素。直白说就是能在组件的切换过程中,将组件的状态保存在内存中,下次打开组件的时候不会重新渲染。

poprs:
include: 字符串或正则表达式,只有匹配的组件会被缓存。
     <keep-alive include="aaa">
        <component></component>
     </keep-alive>
     
exclude:字符串或正则表达式,任何匹配的组件都不会被缓存。
     <keep-alive include="bbb">
        <component></component>
     </keep-alive>
     组件名为bbb的组件不会被缓存。
复制代码
生命钩子
activated:当组件激活时调用。
deactivated:当组件关闭时调用。
注意:组件保存在内存当中,不会被重新创建,所以不会调用created等方法。
复制代码

keep-alive 的实现原理

created和destroyed钩子
/* created钩子会创建一个cache对象,用来作为缓存容器,保存vnode节点。*/
created () {
    /* 缓存对象 */
    this.cache = Object.create(null)
},

/* 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
}
复制代码

优先获取组件的name,没有则获取tag名,再将name或tag通过matches方法判断是否与include或exclude匹配,与exclude匹配成功则不需要缓存,直接返回vnode。与include匹配成功说明需要缓存,在判断cache中是否已经有缓存如果已经有缓存,则直接从缓存中获取,如果还没有缓存则保存到缓存中。

watch

用watch来监听include和exclude的变化。

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

/* 修正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()
  }
}复制代码

转载于:https://juejin.im/post/5b7f6ca151882542d950eb07

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值