Skip to content
On this page

Teleport组件介绍

render(h(Teleport, { to: "#root" }, [123, 456]), app);

Vue3 新增组件,该组件可以将制定内容渲染到制定容器中。默认内容都是渲染到元素app内,我们可以将其渲染到任意节点 (传送门)

const shapeFlag = isString(type)
  ? ShapeFlags.ELEMENT
  : isTeleport(type) // 如果是穿梭框
  ? ShapeFlags.TELEPORT
  : isObject(type)
  ? ShapeFlags.STATEFUL_COMPONENT
  : isFunction(type)
  ? ShapeFlags.FUNCTIONAL_COMPONENT
  : 0; // 函数式组件

创建虚拟节点的时候标识组件类型。

组件挂载

if (shapeFlag & ShapeFlags.TELEPORT) {
  type.process(n1, n2, container, anchor, {
    mountChildren, // 挂载孩子
    patchChildren, // 更新孩子
    move(vnode, container, anchor) {
      // 移动元素
      hostInsert(
        vnode.component ? vnode.component.subTree.el : vnode.el,
        container,
        anchor
      );
    },
  });
}
export const TeleportImpl = {
  __isTeleport: true,
  remove(vnode, unmount) {
    const { shapeFlag, children } = vnode;
    if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
      for (let i = 0; i < children.length; i++) {
        const child = children[i];
        unmount(child);
      }
    }
  },
  process(n1, n2, container, anchor, internals) {
    let { mountChildren, patchChildren, move } = internals;
    if (!n1) {
      // 创建一个目标
      const target = (n2.target = document.querySelector(n2.props.to));
      if (target) {
        mountChildren(n2.children, target, anchor);
      }
    } else {
      patchChildren(n1, n2, container); // 比对儿子
      if (n2.props.to !== n1.props.to) {
        // 更新并且移动位置
        // 获取下一个元素
        const nextTarget = document.querySelector(n2.props.to);
        n2.children.forEach((child) => move(child, nextTarget, anchor));
      }
    }
  },
};
export const isTeleport = (type) => type.__isTeleport;

teleport 卸载

const unmount = (vnode) => {
  const { shapeFlag } = vnode;
  if (vnode.type === Fragment) {
    unmountChildren(vnode.children);
  } else if (shapeFlag & ShapeFlags.COMPONENT) {
    unmount(vnode.component.subTree);
  } else if (shapeFlag & ShapeFlags.TELEPORT) {
    vnode.type.remove(vnode, unmount);
  } else {
    hostRemove(vnode.el);
  }
};

Released under the MIT License.