Virtual DOM 是真实DOM的映射。
当虚拟 DOM 树中的某些节点改变时,会得到一个新的虚拟树。算法对这两棵树(新树和旧树)进行比较,找出差异,然后只需要在真实的 DOM 上做出相应的改变。
/**
* @description 传入node类型的js对象数据,生成Dom
* @param node node类型js对象数据 节点数据
*/
function createElement(node) {
if (typeof node === 'string') {
return document.createTextNode(node);
} else {
const $el = document.createElement(node.type);
node.children.map(createElement).forEach($el.appendChild.bind($el));
return $el;
}
node的类型为:
const node = {
type: "div", // 标签名或者是纯文本
props: {}, // 扩展的功能,如class、id等属性的添加
children: [],// node 类型的js对象数组
};
首先是新节点的添加:
// 不存在老节点,则直接创建新节点
function updateElement($parent, newNode, oldNode,index) {
if (!oldNode) {
$parent.appendChild(createElement(newNode));
}
}
然后是存在oldNode存在而newNode为空的情况:
// 实现移除老节点的操作,index为该节点在父节点的子节点数组中的位序
function updateElement($parent, newNode, oldNode, index) {
if (!oldNode) {
$parent.appendChild(createElement(newNode));
} else if (!newNode) {
$parent.removeChild($parent.childNodes[index]);
}
}
当oldNode,newNode都存在时:
// 节点的替换操作,
function updateElement($parent, newNode, oldNode, index = 0) {
if (!oldNode) {
$parent.appendChild(createElement(newNode));
} else if (!newNode) {
$parent.removeChild($parent.childNodes[index]);
} else if (changed(newNode, oldNode)) {
$parent.replaceChild(createElement(newNode), $parent.childNodes[index]);
}
}
// 需要定义一个工具函数changed(newNode, oldNode),用于比较新老节点之间的差异
function changed(node1, node2) {
return typeof node1 !== typeof node2 ||
typeof node1 === ‘string’ && node1 !== node2 ||
node1.type !== node2.type
}
当新旧节点没有差异时,需要调用updateElement实现递归操作其子节点:
// 完整的节点创建、更新函数
function updateElement($parent, newNode, oldNode, index) {
if (!oldNode) {
$parent.appendChild(createElement(newNode));
} else if (!newNode) {
$parent.removeChild($parent.childNodes[index]);
} else if (changed(newNode, oldNode)) {
$parent.replaceChild(createElement(newNode), $parent.childNodes[index]);
} else if (newNode.type) {
const newLength = newNode.children.length;
const oldLength = oldNode.children.length;
for (let i = 0; i < newLength || i < oldLength; i++) {
updateElement(
$parent.childNodes[index],
newNode.children[i],
oldNode.children[i],
i
);
}
}
}
参考链接:https://mp.weixin.qq.com/s/VHlChNxA7-YQ9HodGb3r_g