Vue.js设计与实现读书笔记十四 第十四章 内建组件和模块

14.1 KeepAlive组件的实现原理

KeepAlive的本质是缓存管理,再加上特殊的挂载/卸载逻辑。KeepAlive组件的实现需要渲染器层面的支持。在keepalive组件卸载时我们不能正的将他卸载,

const cache = new Map();//存储【key,value】 key为插槽组件的vnode.type 而value为插槽组件的vnode
const KeepAlive = {
  __isKeepAlive: true, // KeepAlive组件独有的属性,用作标识
  props: {
    include: RegExp, // KeepAlive的两个属性
    exclude: RegExp
  },
  setup(props, { slots }) {

    const instance = currentInstance // 渲染的时候当前的渲染组件的实例,就是KeepAlive本身的实例
    const { move, createElement } = instance.keepAliveCtx // keepAlive特有的,move是将移动到一个容器中,

    const storageContainer = createElement('div') // 创建隐藏容器

    instance._deActivate = (vnode) => { // 隐藏时候的函数
      move(vnode, storageContainer) //移动到隐藏容器
    }

    instance._activate = (vnode, container, anchor) => {
      move(vnode, container, anchor) // 移除来
    }

    return () => {
      let rawVNode = slots.default() //keepalive的默认插槽
      if (typeof rawVNode.type !== 'object') { // 默认插槽的内容只能是一个组件,并且不能是函数式组件
        return rawVNode  //如果不是直接渲染 没有keepAlive的效果
      }

      const name = rawVNode.type.name // 插槽组件的名字
      if (
        name &&
        (
          (props.include && !props.include.test(name)) ||
          (props.exclude && props.exclude.test(name))
        ) //没有名字或者在排查缓存中的组件,也是没有KeepAlive
      ) {
        return rawVNode
      }

      const cachedVNode = cache.get(rawVNode.type);//获取桶中有没有已经缓存了,插槽中的组件
      if (cachedVNode) { //如果已经缓存了
        rawVNode.component = cachedVNode.component //继承旧的组件实例
        rawVNode.keptAlive = true // 已经被缓存标志
      } else {
        cache.set(rawVNode.type, rawVNode) //没有缓存就缓存他 
      }

      rawVNode.shouldKeepAlive = true //插槽中的组件中,避免渲染器将组件卸载,调用KeepAlive上的_deActivate搬运部
      rawVNode.keepAliveInstance = instance //插槽中的组件添加KeepAlive的组件实例

      return rawVNode //返回职这个被修改后的插槽Vnode
    }
  }
}

KeepAlive的instance上有两个函数_deActivate_activate
KeepAlive的插槽中的组件的Vnode被KeepAlive插入shouldKeepAlivekeepAliveInstance
当组件的卸载的时候:

 function unmount(vnode) {
    if (vnode.type === Fragment) {
      vnode.children.forEach(c => unmount(c))
      return
    } else if (typeof vnode.type === 'object') {
      if (vnode.shouldKeepAlive) { //如果这个组件是被KeepAlive的组件
        vnode.keepAliveInstance._deActivate(vnode) // 调用隐藏组件的方法
      } else {
        unmount(vnode.component.subTree)
      }
      return
    }
    const parent = vnode.el.parentNode
    if (parent) {
      parent.removeChild(vnode.el)
    }
  }

当要重新挂载的时候:

else if (typeof type === 'object' || typeof type === 'function') {
      // component
      if (!n1) {
        if (n2.keptAlive) { //如果新组件已经缓存了
          n2.keepAliveInstance._activate(n2, container, anchor) ;//调用_activate重新挂载
        } else {
          mountComponent(n2, container, anchor)
        }
      } else {
        patchComponent(n1, n2, anchor)
      }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值