vue3中节点的渲染操作主要在runtime-core包中,runtime-core不关心运行的平台。
vue3中通过函数createVNode函数创建一个虚拟节点,其传入三个参数,分别是节点名,属性对象,孩子,如:
const {createVNode,render,h} = VueRuntimeDOM
console.log(createVNode('h1',{key:1},'Hello world'))
可以看到,输出的对象就是一个虚拟节点,其对象包含内容如下:
console.log(h('h1',{key:1},'Hello world'))
h('h1','Hello world')
,内部会将其转换成createVNode('h1,null,'Hello world')
export const enum ShapeFlags { // vue3提供的形状标识
ELEMENT = 1, // 1
FUNCTIONAL_COMPONENT = 1 << 1, // 2
STATEFUL_COMPONENT = 1 << 2, // 4
TEXT_CHILDREN = 1 << 3, // 8
ARRAY_CHILDREN = 1 << 4, // 16
SLOTS_CHILDREN = 1 << 5, // 32
TELEPORT = 1 << 6, // 64
SUSPENSE = 1 << 7, // 128
COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
COMPONENT_KEPT_ALIVE = 1 << 9,
COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
}
export function createVNode(type,props = null, children = null){
// 后续判断有不同类型的虚拟节点
let shapeFlag = isString(type) ? ShapeFlags.ELEMENT : 0 // 标记出来了自己是什么类型
// 我要将当前的虚拟节点 和 自己儿子的虚拟节点映射起来 权限组合 位运算
const vnode = { // vnode 要对应真实际的节点
__v_isVNode:true,
type,
props,
children,
key: props && props.key,
el:null,
shapeFlag
// 打个标记
}
if(children){
let temp = 0;
if(isArray(children)){ // 走到createVnode 要么是数组要么是字符串 h()中会对children做处理
temp = ShapeFlags.ARRAY_CHILDREN
}else{
children = String(children);
temp = ShapeFlags.TEXT_CHILDREN
}
vnode.shapeFlag = vnode.shapeFlag | temp;
}
// shapeFlags 我想知到这个虚拟节点的儿子是数组 还是元素 还是文本
return vnode;
}
export function h(type,propsOrChildren,children){
// h方法 如果参数为两个的情况 1) 元素 + 属性 2) 元素 + 儿子
const l = arguments.length;
if(l === 2){
// 如果propsOrChildren是对象的话 可能是属性 可能是儿子节点
if(isObject(propsOrChildren) && !isArray(propsOrChildren)){ // h(type,属性或者元素对象)
// 要么是元素对象 要么是属性
if(isVnode(propsOrChildren)){ // h(type,元素对象)
return createVNode(type,null,[propsOrChildren])
}
return createVNode(type,propsOrChildren) // h(type,属性)
}else{
// 属性 + 儿子的情况 儿子是数组 或者 字符
return createVNode(type,null,propsOrChildren) // h(type,[] ) h(type,'文本‘)
}
}else{
if(l === 3 && isVnode(children)){ // h(type,属性,儿子)
children = [children]
}else if(l > 3){
children = Array.from(arguments).slice(2)// h(type,属性,儿子数组)
}
return createVNode(type,propsOrChildren,children)
// l > 3
}
}