第八章 挂载与更新
一、挂载子节点和元素的属性
- 第一次 Vnode 渲染为 HTML,并且遍历递归渲染 Vnode 的子节点.
- 遍历 Vnode.props,添加为标签的属性
- 这里遍历是使用
el.setAttribute(key, vnode.props[key])、但是它们有很多问题, - 第一次渲染,或者是新和旧 Vnode 的类型不行等,并且是普通标签,就直接渲染
二、HTML Attibutes 与 DOM Properties
- HTML 中 DOM 的 attibutes 与 properties 的关系
- attitudes 是只用 el.setAttribute() 来添加的属性
- properties 是只直接用 el 添加的属性、两者一般是一对一的,但是也有 attitudes 有的属性,properties 没有,也有反过来的、他们的映射关系不全,甚至有些时候他们的映射是一对多的
- HTML Attitudes 的作用是设置与之对应的 DOM Properties 的初始值。
<input value="aaa" />
当不输入修改 value 的情况下 console.log(el.getAttribute(‘value’))是 aaa, console.log(el[value])的值是 aaa 当修改了 input 中的值,el.value 随之改变,而 el.getAttribute(‘value’)依然是 aaa
三、class 处理
- vue 中 最终希望的结构 class 都为字符串,创建一个函数 normalizaeClass 自动转换为字符串,Vnode 的只要是 class 的值自动会调用这个函数,
- class 设置的方法,el.className 性能最优秀,所以做特别优化,之前的代码是使用 setAttibute,修改为如下优先判断 class 的情况
- 在 Vue 中除了 class 做了增强,style 也做了类似的增强
四、卸载操作
function render(vnode, container) {
if (vnode) {
// 新 vnode 存在,将其与旧 vnode 一起传递给 patch 函数进行打补丁
patch(container._vnode, vnode, container);
} else {
if (container._vnode) {
// 旧 vnode 存在,且新 vnode 不存在,说明是卸载(unmount)操作
unmount(container._vnode);
}
}
// 把 vnode 存储到 container._vnode 下,即后续渲染中的旧 vnode
container._vnode = vnode;
}
function unmount(vnode) {
const parent = vnode.el.parentNode;
if (parent) {
parent.removeChild(vnode.el);
}
// 调用生命周期函数
// 执行各种逻辑
}
container 是一个 DOM 对象,他的_vnode 属性存储着,已经渲染的的子元素的 Vnode Vnode 一旦渲染,他的属性 el 就会存储,他对应的 DOM 对象, 当新的 Vnode 为 null,并且旧的 Vnode 存在,那么就会删除 container 下面的 DOM,也就是卸载
五、Fragment
Vue3支持组件是多个子节点,Vue2不支持,多种子节点就是一个Fragament类型,Fragament不会真的渲染,所以卸载只需要卸载子节点,比较也只需比较子节点 Fragment是没有处理属性的,因为本身不需要真实渲染
const newVnode = {
type: 'div',
children: [
{
type: Fragment,
children: [
{ type: 'p', children: 'text 1' },
{ type: 'p', children: 'text 2' },
{ type: 'p', children: 'text 3' }
]
},
{ type: 'section', children: '分割线' }
]
}
function unmount() {
if (type === Fragment) { //新节点类型是 片段节点,并且新节点与旧节点类型一样
if (!n1) { //旧节点不存在,直接变量children,创建
n2.children.forEach(c => patch(null, c, container))
} else {
patchChildren(n1, n2, container) //处理子节点,注意:这里片段是没有属性的
}
...
}
}