以下代码仅为diff算法的暴力解法,源码更为复杂且高效。mountElement 方法在上一篇文章中
/*
n1: 老节点
n2: 新节点
*/
export function diff(n1, n2) {
// tag
// props
// children
// tag不同直接替换
if (n1.tag !== n2.tag) {
n1.el.replaceWith(document.createElement(n2.tag));
}
else if (n1.props !== n2.props) {
// props不同分为三种情况
// 1.value值发生了变化
// 2.新节点的props增加
// 3.新节点的props减少
// 把el进行交换,保证下一次的diff正确
n2.el = n1.el;
const { props: oldProps } = n1;
const { props: newProps } = n2;
if (newProps) {
Object.entries(newProps).forEach(([key, value]) => {
const oldValue = oldProps[key];
if (value !== oldValue) {
n1.el.setAttribute(key, value);
}
});
}
if (oldProps) {
Object.keys(oldProps).forEach((key) => {
if (!newProps[key]) {
n1.el.removeAttribute(key);
}
});
}
// children 暴力解法
const {children: newChildren} = n2;
const {children: oldChildren} = n1;
if (typeof newChildren === 'string') {
if (typeof oldChildren === 'string') {
if (newChildren !== oldChildren) {
n2.el.textContent = newChildren;
}
}
else if (Array.isArray(oldChildren)) {
n2.el.textContent = newChildren;
}
}
else if (Array.isArray(newChildren)) {
if (typeof oldChildren === 'string') {
n2.el.innerText = ``;
mountElement(n2, n2.el);
}
else if (Array.isArray(oldChildren)) {
// 对比新老children的长度
// 相同长度部分进行递归diff
// newChildren长的部分做创建处理
// oldChildren长的部分做删除处理
const length = Max.min(newChildren.length, oldChildren.length);
for (let i = 0; i < length; i++) {
const newvNode = newChildren[i];
const oldvNode = oldChildren[i];
diff(oldvNode, newvNode);
}
if (newChildren.length > length) {
for (let i = length; i < newChildren.length;i++) {
const newvNode = newChildren[i];
mountElement(newvNode, n2.el);
}
}
if (oldChildren.length > length) {
for (let i = length; i < oldChildren.length; i++) {
const oldvNode = newChildren[i];
// 其实应该是createElement创建出节点,然后删除掉。这里就简单处理了
oldvNode.el.parent.removeChild(oldvNode);
}
}
}
}
}
}