vue3 Teleport源码实现

129 阅读1分钟
export const TeleportImpl = {
  __isTeleport: true, //此组件是一个特殊的组件类型
  process(n1, n2, container, anchor, opreators) {
    //等会组件初始化会调用此方法 
    // mountChildren patchChildren等这几个方法来自renderer方法 详细见文末说明
    let { mountChildren, patchChildren, move, query } = opreators;
    if (!n1) {
      const target = (n2.target = query(n2.props.to)); //querySelector
      if (target) {
        //挂载逻辑
        mountChildren(n2.children, target, anchor); //container不需要了 插入到自己的标签
      }
    } else {
      patchChildren(n1, n2, n1.target); //只是比较儿子的差异 如果是特殊情况
      n2.target = n1.target;
      //如果to 发生了变化 就移动到新节点
      if (n2.props.to !== n1.props.to) {
        const nextTarget = (n2.target = query(n2.props.to));
        n2.children.forEach((child) => move(child, nextTarget, anchor));
      }
    }
  },
};
  • 使用
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app" style="width: 100px; height: 100px; overflow: hidden"></div>
    <div id="root"></div>
    <div id="home"></div>
    <script type="module">
       // 导入Teleport
      import { Teleport, h, Fragment, render } from "./runtime-dom.esm.js";
      render(h(Teleport, { to: "#root" }, [h("div", "teleport")]), app);
      setTimeout(() => {
        render(h(Teleport, { to: "#home" }, [h("div", "teleport")]), app);
      }, 2000);
    </script>
  </body>
</html>
//对TeleportImpl的补充说明 刻可以查询renderer.js进行理解
//一下几个方法来自renderder.js中
//querySelector: hostQuerySelect,
query: hostQuerySelect
move(vnode, container, anchor) {
  hostInsert(
    vnode.component ? vnode.component.subTree.el : vnode.el,
    container,
    anchor
  );
},