除了元素虚拟节点之外,Vue3中还有很多其他类型的虚拟节点,这里我们先来说下Text和Fragment的实现
export const Text = Symbol('Text')
export const Fragment = Symbol('Fragment')
1
2
2
文本类型
renderer.render(h(Text,'jw handsome'),document.getElementById('app'))
1
const patch = (n1,n2,container,anchor?) => {
// 初始化和diff算法都在这里喲
if(n1 == n2){return }
if(n1 && !isSameVNodeType(n1,n2)){ // 有n1 是n1和n2不是同一个节点
unmount(n1)
n1 = null
}
const {type,shapeFlag} = n2;
switch(type){
case Text:
processText(n1,n2,container); // 处理文本
break;
case Fragment:
processFragment(n1,n2,container); // 处理fragment
break;
default:
if(shapeFlag & ShapeFlags.ELEMENT){
processElement(n1,n2,container,anchor); // 之前处理元素的逻辑
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const processText = (n1,n2,container)=>{
if(n1 == null){
hostInsert((n2.el = hostCreateText(n2.children)),container)
}else{
const el = n2.el = n1.el;
if(n2.children !== n1.children){
hostSetText(el,n2.children)
}
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Fragment类型
renderer.render(h(Fragment,[h(Text,'hello'),h(Text,'jw')]),document.getElementById('app'))
1
const processFragment = (n1,n2,container)=>{
if(n1 == null){
mountChildren(n2.children,container);
}else{
patchChildren(n1,n2,container);
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
为了让Vue3支持多根节点模板,Vue.js 提供Fragment来实现,核心就是一个无意义的标签包裹多个节点。
同时这里要处理下卸载的逻辑,如果是fragment则删除子元素
const unmount = (vnode) =>{
if(vnode.type === Fragment){
return unmountChildren(vnode.children)
}
hostRemove(vnode.el)
}
1
2
3
4
5
6
2
3
4
5
6
← Vue3 Diff算法 组件渲染 →