第二十二章 vue3的shapeFlags实现

236 阅读1分钟

vue3的shapeFlags实现

shapeFlags最主要的作用就是标识虚拟节点的类型,但其实如果只是为了标识类型查改方便,对象已经符合了我们所想要做的操作,为什么还需要用二进制来做的,主要还是二进制查改的效率更高。

二进制复习。注:| 都是0才为0 用于修改 & 都是1才为1 用于查找

首先,先定义shapeFlags文件,该文件导出一个枚举的shapeFlags,其中包含了四个类型的的枚举值,如图所示:

image.png

接着,我们需要到虚拟节点vnode中增加一个shapeFlag的标识属性,通过vnode中的type给他初始化类型,然后当他有children属性时,需要对虚拟节点的shapeFlag属性进行修改,如图:

image.png

然后,vnode拥有了shapeFlag状态之后,我们就可以将render文件中通过虚拟节点type判断的操作进行优化了,如图:

image.png

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)
}