Vue源码之虚拟DOM和diff算法 01 虚拟DOM和h函数

136 阅读2分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

虚拟DOM

虚拟DOM指:用JavaScript描述DOM的层次结构。DOM中的一切属性都在虚拟DOM中有对应的属性。

真实DOM:

image.png

虚拟DOM:

image.png

diff是发生在虚拟DOM上的: 新虚拟DOM和老虚拟DOM进行diff(精细化比较),算发出应该如何最小量更新,最后反映到真正的DOM上。

h函数

作用:用来产生虚拟节点(vnode)
举例:
这样调用h函数:

h('a',{props:{href:"https://juejin.cn/"}},"掘金"};

将得到这样的虚拟节点:

{sel:"a",data:{props:{href:"https://juejin.cn/"}},text:"掘金"};

他表示的真正的DOM节点:

<a href="https://juejin.cn/">掘金</a>

虚拟节点的属性

属性分别为:children、data、elm、key、sel、text

var vnode = h(
    'a', {
        props: {
            href: 'https://juejin.cn/',
            target: "_blank",
        },
    },
    '掘金',
)

image.png

h函数可以嵌套使用,从而得到虚拟DOM树: h函数的用法很活,不一定要按着模板书写。

    h("li", "倒霉死勒"),
    h("li", "林予曦"),
    h("li", [
        h("p", "苏尚卿"),
        h("p", "谷江山"),
    ]),
    h("li", h("p", "锦鲤")),
    ])

image.png

手写h函数

h函数的形式有很多,比如: h("div"), h("div",{},),h("div",{},"text"),这里指讨论h函数必须传入三个参数的情况,即必须传入sel、data和第三个参数(可以是text、array、object)

vnode函数:功能很简单,只是将传入的参数转换成一个对象返回。

export default function (sel, data, children, text, elm) {
    return {
        sel,
        data,
        children,
        text,
        elm
    }
}

h函数:主要函数,将传入的参数转换成对象。

export default function (sel, data, c) {
    if (arguments.length != 3) {
        throw new Error("must three elements");
    }
    if (typeof c == "string" || typeof c == "number") {
        return vnode(sel, data, undefined, c, undefined);
    } else if (Array.isArray(c)) {
        let children = [];
        for (let i = 0; i < c.length; i++) {
            if (!(typeof c[i] == "object" && c[i].hasOwnProperty("sel"))) {
                throw new Error("数组中有项类型不对");
            }
            children.push(c[i]);
        }
        return vnode(sel, data, children, undefined, undefined)
    } else if (typeof c == "object" && c.hasOwnProperty("sel")) {
        let children = [c];
        return vnode(sel, data, children, undefined, undefined)
    } else {
        throw new Error("传入类型不正确");
    }
}

步骤:

  • 第一步:检查参数的个数;
  • 第二步:因为第一个参数必须是sel,第二个参数必须是data,所以检查第三个参数的类型;

判断第三个参数:
1、如果第三个参数是简单数据类型,如字符串或数字类型,可以直接作为text属性的属性值返回;
2、如果第三个参数是数组类型,则将数组子项作为children返回; 3、如果第三个参数是对象类型,则就可视为唯一的children子项。