更新节点patchVnode
更新节点概念
分为一下几种情况:
- 新节点是内容是text文字,此时将旧节点的内容更新为文字(无论旧DOM的子节点是何种形式,因为本笔记不考虑混合情况)
- 新节点是内容是h函数,此时将节点的h函数创建为真实DOM并替换旧DOM的子节点。
- 新节点是Array,此时需要分类讨论
- 若旧节点是文字或者h函数,①清空老节点 ②将Array依次创建为DOM并插入老DOM
- 若旧节点也是Array,此时我们需要实现最小化更新,及:找到子节点中相同的节点更新节点并将节点对应的DOM放至到更新后的位置,删除不要的节点,新增新增的节点,也就是我们所说的diff算法。
- 更新结束之后将最新的DOM指向新vnode的elm
更新节点语法
// patchVnode
import createElement from "./createElement"
// 最小化更新函数,下一篇介绍
import updateChildren from "./updateChildren"
// 移除所有子节点
function removeAllChildren(element) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
export default function patchVnode(oldVnode, newVnode) {
// 内存中是同一节点
if (oldVnode === newVnode) return
// 判断新vnode有没有text属性
if (newVnode.text && (newVnode.children === undefined || newVnode.children.length === 0)) {
// 新vnode有且仅有text属性
if (newVnode.text !== oldVnode.text) {
oldVnode.elm.innerText = newVnode.text
}
}
else if (newVnode.children && !Array.isArray(newVnode.children)) {
// 新节点是h函数
let dom = createElement(newVnode.children)
removeAllChildren(oldVnode.elm)
oldVnode.elm.appendChild(dom)
}
else if (newVnode.children && Array.isArray(newVnode.children) && newVnode.children.length > 0) {
// 新节点有且仅有非文字子节点
// 判断老节点类型
if (oldVnode.children && oldVnode.children.length > 0) {
// 老节点是数组->最小化更新,下一篇具体描述
updateChildren(oldVnode.elm, oldVnode.children, newVnode.children)
} else {
// 老节点是文字orvnode
removeAllChildren(oldVnode.elm)
for (let i = 0; i < newVnode.children.length; i++) {
let dom = createElement(newVnode.children[i])
oldVnode.elm.appendChild(dom)
}
}
}
newVnode.elm = oldVnode.elm
}