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
  );
}
相关文章
|
14天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
118 64
|
14天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
|
14天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
26 8
|
14天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
19 1
|
14天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
27 1
|
14天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
18天前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
31 0
|
18天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
20天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
21天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
24 1
vue学习第一章