vue3的shapeFlags实现
shapeFlags最主要的作用就是标识虚拟节点的类型,但其实如果只是为了标识类型查改方便,对象已经符合了我们所想要做的操作,为什么还需要用二进制来做的,主要还是二进制查改的效率更高。
二进制复习。注:| 都是0才为0 用于修改 & 都是1才为1 用于查找
首先,先定义shapeFlags文件,该文件导出一个枚举的shapeFlags,其中包含了四个类型的的枚举值,如图所示:
接着,我们需要到虚拟节点vnode中增加一个shapeFlag的标识属性,通过vnode中的type给他初始化类型,然后当他有children属性时,需要对虚拟节点的shapeFlag属性进行修改,如图:
然后,vnode拥有了shapeFlag状态之后,我们就可以将render文件中通过虚拟节点type判断的操作进行优化了,如图:
shapeFlags.ts
// 使用对象可以满足查和改的操作 -- 为了提升效率是 --> 使用二进制效率更高
export const enum shapeFlags {
ELEMENT = 1, //0001
STATEFUL_COMPONENT = 1 << 1, //0010
TEXT_CHILDREN = 1 << 2, //0100
ARRAY_CHILDREN = 1 << 3 //1000
}
vnode.ts
import { shapeFlags } from "./shapeFlags"
export function createVNode(type,props?,children?){
const vnode = {
type,
props,
children,
shapeFlag:getShapeFlag(type),
el: null
}
// children
if(typeof children === 'string'){
vnode.shapeFlag |= shapeFlags.TEXT_CHILDREN
} else if(Array.isArray(children)){
vnode.shapeFlag |= shapeFlags.ARRAY_CHILDREN
}
return vnode
}
function getShapeFlag(type){
return typeof type === 'string' ? shapeFlags.ELEMENT : shapeFlags.STATEFUL_COMPONENT
}
render.ts,主要修改到的代码是patch函数和mountElement函数:
function patch(vnode,container){
const {shapeFlag} = vnode
if(shapeFlag & shapeFlags.ELEMENT){
processElement(vnode,container)
} else if(shapeFlag & shapeFlags.STATEFUL_COMPONENT){
processComponent(vnode,container)
}
}
function mountElement(vnode,container){
// 保存根节点到vnode上
const el = ( vnode.el = document.createElement(vnode.type))
const {children,props,shapeFlag} = vnode
// children
if(shapeFlag & shapeFlags.TEXT_CHILDREN) {
el.textContent = children
} else if(shapeFlag & shapeFlags.ARRAY_CHILDREN) {
mountChildren(children,el)
}
// props
for(const key in props){
const val = props[key]
el.setAttribute(key,val)
}
container.append(el)
}