除了元素虚拟节点之外,Vue3中还有很多其他类型的虚拟节点,这里我们先来说下Text和Fragment的实现

export const Text = Symbol('Text')
export const Fragment = Symbol('Fragment')
1
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
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

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

为了让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