手写虚拟dom与domDiff

1、dom与虚拟dom
dom全称document object module 文件对象模型。顾名思义,就是当html渲染到浏览器上时,构成html文档的元素就是dom。
虚拟dom本质上是一个对象,大概如以下结构:

     vNode={
           key:null,
           type:"div",
           props:{children:[] ,onclick:()=>{},className:""}
     }

虚拟dom的优点:

  • 减少dom操作的次数 比如要向⻚面添加1000次div,如果用原生js,要操作dom1000次,但通过虚拟dom和dom算法,只 需要一次操作。
  • 减少dom操作的范围 要更新dom里面某个节点的innnerHtml,比如里面有1000个div,里面有900个是旧的,如果用原生 js,那么要把它们都删掉重写,但是通过dom diff,可以直接保留原先的然后插入新的。
  • 跨平台 虚拟dom不仅可以变成dom还可以变成小程序,ios应用,安卓应用,因为它本质上是一个js对象。
    虚拟dom缺点: 需要创建新的函数,如React.CreateElement,但是可以通过引入jsx进行简化。
    2、手写虚拟dom
class VNode {
    type;
    text;
    props = { children: [] }
    constructor(type, property, children, text) {
        this.type = type;
        this.props.children = children;
        if (type === "#text") this.text = text;
        for (let key in property) {
            this.props[key] = property[key]
        }
    }
    render() {
        if (this.type === "#text") return document.createTextNode(this.text);
        let el = document.createElement(this.type);
        for (let key in this.props) {
            if (key !== "children") {
                el[key] = this.props[key]
            }
        };
        this.props.children.forEach(VNode => {
            el.appendChild(VNode.render())
        })
        return el;
    }
}
const v = (type, property, children, text) => {
    return new VNode(type, property, children, text);
}

const test = () => {
    const el = v("div", { onclick: () => { console.log(1) } }, [
        v("span", {}, [
            v("#text", {}, [], "hello ")
        ]),
        v("#text", {}, [], "world")
    ]);
    document.getElementById("root").appendChild(el.render())
}
text()

3、手写domDiff
这里实现简单的diff算法,不考虑改变绑定事件等属性

const patchesVNode = (parent, newVNode, oldVNode, index = 0) => {

    console.log(parent.childNodes)
    if (!oldVNode) {
        parent.appendChild(newVNode.render());
    } else if (!newVNode) {
        parent.removeChild(parent.childNodes[index]);
    } else if (newVNode.type !== oldVNode.type || newVNode.text !== oldVNode.text) {
        parent.replaceChild(newVNode.render(), parent.childNodes[index]);
    } else {
        for (let i = 0; i < newVNode.props.children.length || i < oldVNode.props.children.length; i++) {
            patchesVNode(parent.childNodes[index], newVNode.props.children[i], oldVNode.props.children[i], i)
        }
    }
}

你可能感兴趣的:(手写虚拟dom与domDiff)