patchChildren(n1,n2,container) 当新、旧在子节点的类型都是元素类型时,调用 patchChildren()进行对新节点进行更新
Vue3 元素子节点的三种规范
元素子节点的三种规范:
- 没有子节点 node.children = null
- 一个字符串子节点 node.children = 'string'
- 数组子节点,里面包含各种类型的子节点
```js
// 元素子节点的 type 都是字符串
// 1
const vnode = [
{
type: 'p',
children: null,
},
]
// 2
const vnode = [
{
type: 'p',
children: '',
},
]
// 3
const vnode = [
{
type: 'p',
children: [
{
type: 'span',
children: 'text',
},
null,
'some text',
],
},
]
```
新旧子节点的9种类型
- 新子节点 为 null
- 旧子节点 为 null **(清空就行,setElementText(el, ''))**
- 旧子节点 为 字符串 **(清空就行,setElementText(el, ''))**
- 旧子节点 为 数组 **(逐个卸载就行)**
- 新子节点 为 字符串
- 旧子节点 为 null **(更新内容,setElementText(el,newValue))**
- 旧子节点 为 字符串 **(更新内容,setElementText(el,newValue))**
- 旧子节点 为 数组 **(先卸载所有的旧子节点,然后更新内容,setElementText(el,newValue))**
- 新子节点 为 数组
- 旧子节点 为 null **(清空容器 setElementText(el, ''),逐个挂载新子节点)**
- 旧子节点 为 字符串 **(清空容器 setElementText(el, ''),逐个挂载新子节点)**
- 旧子节点 为 数组 **(核心 diff 算法,比较两组差异)**
api解析
/**
* 更新节点
* 新旧子节点共有9种情况,渲染器.md 426 有详细注释
* @param {*} n1
* @param {*} n2
* @param {*} container
*/
function patchChildren(n1, n2, container) {
if (typeof n2.children === 'string') {
/**
* 处理 新子节点为字符串的情况
* 这种情况下 旧子节点 为 null | string 都不需要特殊处理
* 只需要处理旧子节点为数组的情况,需要卸载旧子节点
*
*/
if (Array.isArray(n1.children)) {
// 旧子节点为数组的情况,需要卸载旧子节点
n1.children.forEach((node) => unmount(node))
}
setElementText(container, n2.childern) // 最后都把内容置为字符串
} else if (Array.isArray(n2.children)) {
/**
* 处理 新子节点 为数组的情况
*/
if (Array.isArray(n1.children)) {
/**
*
* 旧子节点为数组,diff算法
* diff 算法
*/
} else {
/**
*
* 旧子节点为字符串 | 为 null
* 清空容器,逐个挂载新子节点
*/
setElementText(container, '')
n2.children.forEach((node) => patch(null, node, container))
}
} else {
/**
* 新子节点为 null
*
*/
if (Array.isArray(n1.children)) {
// 旧子节点为数组,逐个卸载
n1.children.forEach((node) => unmount(node))
} else if (typeof n1.children === 'string') {
// 字符串的子节点,清空容器
setElementText(container, '')
}
// 为 null 就表示没有子节点,无需处理
}
}