Skip to content
On this page

除了元素虚拟节点之外,Vue3 中还有很多其他类型的虚拟节点,这里我们先来说下 Text 和 Fragment 的实现

export const Text = Symbol("Text");
export const Fragment = Symbol("Fragment");

文本类型

render(h(Text, "jw handsome"), document.getElementById("app"));
const patch = (n1, n2, container, anchor?) => {
  // 初始化和diff算法都在这里喲
  if (n1 == n2) {
    return;
  }
  if (n1 && !isSameVNodeType(n1, n2)) {
    // 有n1 是n1和n2不是同一个节点
    unmount(n1);
    n1 = null;
  }
  const { type, shapeFlag } = n2;
  switch (type) {
    case Text:
      processText(n1, n2, container); // 处理文本
      break;
    case Fragment:
      processFragment(n1, n2, container); // 处理fragment
      break;
    default:
      if (shapeFlag & ShapeFlags.ELEMENT) {
        processElement(n1, n2, container, anchor); // 之前处理元素的逻辑
      }
  }
};
const processText = (n1, n2, container) => {
  if (n1 == null) {
    hostInsert((n2.el = hostCreateText(n2.children)), container);
  } else {
    const el = (n2.el = n1.el);
    if (n2.children !== n1.children) {
      hostSetText(el, n2.children);
    }
  }
};

Fragment 类型

render(
  h(Fragment, [h(Text, "hello"), h(Text, "jw")]),
  document.getElementById("app")
);
const processFragment = (n1, n2, container) => {
  if (n1 == null) {
    mountChildren(n2.children, container);
  } else {
    patchChildren(n1, n2, container);
  }
};

为了让 Vue3 支持多根节点模板,Vue.js 提供 Fragment 来实现,核心就是一个无意义的标签包裹多个节点。

同时这里要处理下卸载的逻辑,如果是 fragment 则删除子元素

const unmount = (vnode) => {
  if (vnode.type === Fragment) {
    return unmountChildren(vnode.children);
  }
  hostRemove(vnode.el);
};

Released under the MIT License.