Vue3之Teleport实现原理

简介: Vue3之Teleport实现原理

Teleport官方文档

源码位置:
runtime-core/src/components/Teleport

我们都知道渲染组件是由渲染器完成,Teleport当然也是一个组件,只不过它比较特殊而已。

特殊就在于该组件的渲染逻辑不应该放在渲染器中,因为如果没有使用到该组件,通过树摇最终的构建包不会包含这部分代码。另外也是为了给渲染器 瘦身 哈!

所以需要在patch函数中判断是否是Teleport组件,再将控制权交还给Teleport组件,另外会再将一些渲染器的方法也传递给Teleport

else if (typeof type === 'object' && type.__isTeleport) {
   
   // 组件选项中如果存在 __isTeleport 标识,则它是 Teleport 组件,
   // 调用 Teleport 组件选项中的 process 函数将控制权交接出去
   type.process(n1, n2, container, anchor, {
   
   patch,
   patchChildren,
   unmount,
   move(vnode, container, anchor) {
   
   insert(vnode.component ? vnode.component.subTree.el :
  ode.el, container, anchor)
   }
   })
   }

对于组件来说,例如keppAlive组件的子节点会被编译为插槽内容, 不过对于 Teleport 组件来说,直接将其子节点编译为一个数组即可

//代表Teleport组件的VNode
{
   
 type: Teleport,
 // 以普通 children 的形式代表被 Teleport 的内容
 children: [
 {
    type: 'h1', children: 'Title' },
 {
    type: 'p', children: 'content' }
 ]
 }

如果是第一次挂载,需要根据Teleport组件上的to属性找到挂载点,接着将组件内的元素循环放在挂载点之下

process(n1, n2, container, anchor, internals) {
   
  // 通过 internals 参数取得渲染器的内部方法
  const {
    patch } = internals
  // 如果旧 VNode n1 不存在,则是全新的挂载,否则执行更新
  if (!n1) {
   
    // 挂载
    // 获取容器,即挂载点
    const target = typeof n2.props.to === 'string'
      ? document.querySelector(n2.props.to)
      : n2.props.to
    // 将 n2.children 渲染到指定挂载点即可
    n2.children.forEach(c => patch(null, c, target, anchor))
  }
  else {
   
    //更新
  }
}

对于更新,只需要调用patchChildren比较子节点并替换。但是如果是Teleport组件的to属性改变了,代表要修改挂载点。因为子节点已经被替换,所以只需要移动到新的挂载点即可。

但是对于组件(vnode.component.subTree.el)和普通标签(vnode.el)实例存放的位置不一样,需要区分.所以渲染器传递的move函数封装了insert函数返回给Teleport使用,另外对于文本节点,片段也需要判断,这里只介绍这两种情况。

else {
   
      // 更新
      patchChildren(n1, n2, container);
      // 如果新旧 to 参数的值不同,则需要对内容进行移动
      if (n2.props.to !== n1.props.to) {
   
        // 获取新的容器
        const newTarget =
          typeof n2.props.to === "string"
            ? document.querySelector(n2.props.to)
            : n2.props.to;
        // 移动到新的容器
        n2.children.forEach((c) => move(c, newTarget));
      }
    }
move(vnode, container, anchor) {
   
  insert(
    vnode.component
      ? vnode.component.subTree.el // 移动一个组件
      : vnode.el, // 移动普通元素
    container,
    anchor
  );
}
相关文章
|
7天前
|
JavaScript API
Vue3中的计算属性能否动态修改
【9月更文挑战第5天】Vue3中的计算属性能否动态修改
38 10
|
2天前
|
前端开发
vue3+ts项目中使用mockjs
vue3+ts项目中使用mockjs
189 57
|
7天前
|
JavaScript API
如何使用Vue3的可计算属性
【9月更文挑战第5天】如何使用Vue3的可计算属性
40 13
|
7天前
|
资源调度 JavaScript API
vue3 组件通信方式
vue3 组件通信方式
36 11
|
7天前
|
缓存 JavaScript API
Vue3— computed的实现原理
【9月更文挑战第5天】Vue3— computed的实现原理
28 10
|
9天前
|
存储 JavaScript 前端开发
Vue 3的响应式系统是如何工作的呢
【9月更文挑战第3天】Vue 3的响应式系统是如何工作的呢
20 4
|
9天前
|
缓存 JavaScript API
介绍一下Vue 3的响应式系统
【9月更文挑战第3天】介绍一下Vue 3的响应式系统
26 3
|
4月前
|
JavaScript API
【vue实战项目】通用管理系统:api封装、404页
【vue实战项目】通用管理系统:api封装、404页
65 3
|
4月前
|
人工智能 JavaScript 前端开发
毕设项目-基于Springboot和Vue实现蛋糕商城系统(三)
毕设项目-基于Springboot和Vue实现蛋糕商城系统
|
4月前
|
JavaScript Java 关系型数据库
毕设项目-基于Springboot和Vue实现蛋糕商城系统(一)
毕设项目-基于Springboot和Vue实现蛋糕商城系统
140 0