Appearance
处理边界情况
本节目标:理解“处理边界情况”的核心思路,并能把它用于实际开发或面试表达。
文本的处理, 需要自己增加类型。因为不能通过document.createElement('文本')
h(
'h1',
{
style: { color: 'red' },
onClick: () => alert(1)
},
[
h('span', '123'),
'123'
]
)vnode.ts添加一个类型标识Text
import { isArray, isString, ShapeFlags } from "@vue/shared";
export const Text = Symbol('Text')这样的话,
let shapeFlag = isString(type) ? ShapeFlags.ELEMENT : 0;
得到shapeFlag为0;之后if (children) {
let type = 0;
if (isArray(children)) {
type = ShapeFlags.ARRAY_CHILDREN;
} else {
children = String(children);
type = ShapeFlags.TEXT_CHILDREN;
}
vnode.shapeFlag |= type
}
这里的最终结果是vnode.shapFlag的值为ShapeFlags.ARRAY_CHILDREN或者ShapeFlags.TEXT_CHILDREN,就像没有赋予权限一样的接下来,在renderer.ts的patch方法中,添加一个逻辑:
const patch = (n1, n2, container) => {
if (n1 === n2) return;
const { type, shapeFlag } = n2
switch (type) {
case Text:
processText(n1, n2, container);
break;
default:
if (shapeFlag & ShapeFlags.ELEMENT) {
processElement(n1, n2, container);
}
}
}const processText = (n1, n2, container) => {
if (n1 === null) {
hostInsert((n2.el = hostCreateText(n2.children)), container)
} else {
// 文本的内容变化了,我可以复用老的节点
const el = n2.el = n1.el;
if (n1.children !== n2.children) {
hostSetText(el, n2.children); // 文本的更新
}
}
}在mountChildren中,还要进行处理:
const mountChildren = (children, container) => {
for (let i = 0; i < children.length; i++) {
let child = normalize(children[i])
patch(null, child, container)
}
}const normalize = (child) => {
if (isString(child)) {
return createVnode(Text, null, child)
}
return child
}