霍春阳版
2023年08月30日
一、实现
const patchChildren = (n1, n2, container, anchor) => {
const c1 = n1 && n1.children;
const c2 = n2.children;
if (typeof c2 === 'string') {
/**
* @description: 分支一: 如果新子节点为字符串
* 旧子节点没有子节点: 不做事情
* 旧子节点为文本节点: 不做事情
* 旧子节点为数组: 逐个卸载
*/
if (Array.isArray(n1.children)) {
n1.children.forEach(c => unmount(c));
}
hostSetElementText(container, c2);
} else if (Array.isArray(c2)) {
/**
* @description: 分支二: 如果新子节点为数组
* 旧子节点没有子节点: 清空容器
* 旧子节点为文本节点: 清空容器
* 旧子节点为数组: Diff 算法
*/
if (Array.isArray(n1.children)) {
/**
* @description: 新子节点为数组, 旧子节点为数组, 进行 Diff 算法
*/
patchKeyedChildren(c1, c2, container, anchor);
} else {
/**
* @description: 新子节点为数组, 旧子节点为单个节点, 将容器元素清空, 将新子节点数组逐个挂载到容器中
*/
hostSetElementText(container, '');
c2.forEach(c => patch(null, c, container));
}
} else {
/**
* @description: 分支三: 如果新子节点为空
* 旧子节点没有子节点: 不做事情
* 旧子节点为文本节点: 清空容器
* 旧子节点为数组: 逐个卸载
*/
if (Array.isArray(c1)) {
c.forEach(c => unmount(c));
} else if (typeof c1 === 'string') {
hostSetElementText(container, '');
}
}
};
二、测试
import { watch } from './reactivity/watch';
import { effect } from './reactivity/effect';
import { computed } from './reactivity/computed';
import { patchProp } from './runtime-core/patchProp';
import { jobQueue, flushJob } from './reactivity/scheduler';
import { reactive, shallowReactive, readonly } from './reactivity/reactive';
import {
createRenderer,
Text,
Comment,
Fragment
} from './runtime-core/renderer';
const renderOps = {
createElement(tag) {
return document.createElement(tag);
},
setElementText(el, text) {
el.textContent = text;
},
insert(el, parent, anchor = null) {
parent.insertBefore(el, anchor);
}
};
const renderer = createRenderer({ ...renderOps, patchProp });
const data = reactive({ msg: 'Hello World' });
effect(() => {
const vnode = {
type: 'div',
shapeFlag: 9,
props: {
id: 'id-div',
style: {
color: 'red'
},
class: 'class-div',
onClick: [
() => {
console.log('1');
},
() => {
console.log('2');
}
]
},
children: [
{
type: 'h3',
shapeFlag: 9,
children: data.msg
}
]
};
renderer.render(vnode, document.querySelector('#app'));
});
setTimeout(() => {
data.msg = 'Hello World 修改';
}, 3000);