跳至主要內容

11. 实现 Text 和 Fragment


11. 实现 Text 和 Fragment

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

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

1.文本类型

render(h(Text, 'erxiao 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);
		}
	}
};

2.Fragment 类型

render(
	h(Fragment, [h(Text, 'hello'), h(Text, 'erxiao')]),
	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);
};