虚拟dom

257 阅读2分钟

虚拟dom以及其优点

什么是虚拟dom

虚拟DOM可以认为就是,用JS去按照DOM结构来实现的树形结构对象,你也可以叫做DOM对象;

虚拟dom优点

  • 虚拟Dom可以用于SSR以及跨端使用;
  • 可以降低使用JavaScript去操作跨线程的庞大Dom所需要的昂贵性能,让Dom操作的性能更高;
  • 在去任何手动优化的情况下为你提供不错的性能;

注意: 虚拟dom并不会比真实的都没快,dom-diff不是免费的,但是虚拟dom是在你没有任何手动优化的情况下都给你提供不错的性能,更多关于虚拟dom是不是比真实dom快的文章可以看:尤大知乎回答

虚拟dom实现

创建虚拟dom

创建虚拟dom就是用js对象表示dom对象,具体代码如下:

// 创建虚拟DOM元素的类,构建实例对象,就是用来描述DOM
class Element {
    constructor(type, props, children) {
        this.type = type;
        this.props = props;
        this.children = children;
    }
}
// 创建虚拟DOM,返回虚拟节点(object)
function createElement(type, props, children) {
    return new Element(type, props, children);
}

vue和react也是用这种方法来创建虚拟dom的,该方法接受三个参数分别是type,props和children,

  • type:元素类型,例如 "li"、"div"等;
  • props:元素身上的属性,如class, style, 自定义属性等;
  • children:以数组的形式传入,表示元素子节点;

渲染虚拟dom

渲染阶段是将虚拟都没转化成真是dom的过程,在该过程中对虚拟dom进行递归遍历,并对元素设置相关属性;

// render方法可以将虚拟DOM转化成真实DOM
function render(domObj) {
    // 根据type类型来创建对应的元素
    let el = document.createElement(domObj.type);
    
    // 再去遍历props属性对象,然后给创建的元素el设置属性
    for (let key in domObj.props) {
        // 设置属性的方法
        setAttr(el, key, domObj.props[key]);
    }
    
    // 遍历子节点
    // 如果是虚拟DOM,就继续递归渲染
    // 不是就代表是文本节点,直接创建
    domObj.children.forEach(child => {
        child = (child instanceof Element) ? render(child) : document.createTextNode(child);
        // 添加到对应元素内
        el.appendChild(child);
    });

    return el;
}

// 设置属性
function setAttr(node, key, value) {
    switch(key) {
        case 'value':
            // node是一个input或者textarea就直接设置其value即可
            if (node.tagName.toLowerCase() === 'input' ||
                node.tagName.toLowerCase() === 'textarea') {
                node.value = value;
            } else {
                node.setAttribute(key, value);
            }
            break;
        case 'style':
            // 直接赋值行内样式
            node.style.cssText = value;
            break;
        default:
            node.setAttribute(key, value);
            break;
    }
}

// 将元素插入到页面内
function renderDom(el, target) {
    target.appendChild(el);
}

小结

这以上是虚拟dom的实现,github地址为:github地址