[vue小知识] 虚拟DOM

本文介绍了Vue.js中的虚拟DOM概念,包括什么是虚拟DOM、render函数的作用,以及createElement核心方法、render方法、元素属性设置、递归设置子属性的细节。还深入探讨了DOM Diff和Patch过程,阐述了虚拟DOM如何通过Diff算法找到最小更新策略,并通过打补丁更新真实DOM,以实现高效UI更新。
摘要由CSDN通过智能技术生成

目录

什么是虚拟DOM

什么是render函数

createElement核心方法

render核心方法

元素设置属性

递归设置子属性

真实DOM渲染到浏览器上

DOM Diff

Patch 打补丁

DOM-diff  的过程:


什么是虚拟DOM

虚拟dom是相对于浏览器所渲染出来的真实dom而言的. 在vue和react技术出现之前,如果想要修改页面展示的内容,只能通过遍历查询DOM树的方式查找要修改的dom元素进行操作,从而达到更新ui的目的.

这种方式相当消耗计算资源,因为每次查找DOM元素,几乎要遍历整棵DOM树,所以就建立了一个与DOM树相对应的虚拟DOM对象,简单理解就是javascript对象

以对象嵌套的方法来表示DOM树的层级结构,那么每次DOM的更改就变成了js对象属性的增删改查,这样一来查找对象属性的方法就比查找DOM树的性能开销要小

简单来说,虚拟DOM就是用js对象来模拟真实DOM,然后通过render方法,将它渲染成真实DOM

什么是render函数

简单来说,在vue中我们使用模板HTML语法来组建页面,而使用render函数我们可以用js语言来构建DOM, 因为vue是虚拟DOM,所以在拿到template模板时也要转译成VNode的函数,而用render构建DOM,就免去了转译的过程

当使用render函数描述虚拟DOM时,vue提供了一个函数,官网给它起了一个名字叫createElement,还约定它的简写叫 h

createElement核心方法

createElement 接受typeprops,children三个参数创建一个虚拟标签元素DOM的方法。

function createElement(type, props, children) {
    return new Element(type, props, children);
}

为了提高代码高度的复用性,我们将创建虚拟DOM元素的核心逻辑代码放到Element类中。

class Element {
    constructor(type, props, children) {
        this.type = type;
        this.props = props;
        this.children = children;
    }
}

注意:将这些参数挂载到该对象的私有属性上,这样在new时也会有这些属性。 

render核心方法

render方法接受一个虚拟节点对象参数,其作用是:将虚拟DOM转换成真实DOM

function render(eleObj) {
    let el = document.createElement(eleObj.type); // 创建元素
    for(let key in eleObj.props) {
        // 设置属性的方法
        setAttr(el, key, eleObj.props[key])
    }
    eleObj.children.forEach(child => {
        // 判断子元素是否是Element类型,是则递归,不是则创建文本节点
        child = (child instanceof Element) ? render(child) : document.createTextNode(child);
        el.appendChild(child);
    });
    return el;
}

元素设置属性

在给元素设置属性的公共方法中接受三个参数:node,key,value分别表示给那个元素设置属性、设置的属性名、以及设置属性的值。

function setAttr(node, key, value) {
    switch(key) {
        case 'value': // node是一个input或者textarea
            if(node.tagName.toUpperCase() === 'INPUT' || node.tagName.toUpperCase() === 'TEXTAREA') {
                node.value = value;
            } else { // 普通属性
                node.setAttribute(key, value);
            }
        break;
        case 'style':
            node.style.cssText = value;
        break;
        default:
            node.setAttribute(key, value);
        break;
    }
}

递归设置子属性

判断子元素是否是Element元素类型,是则递归,不是则创建文本节点。

注意:我们只考虑了元素类型和文本类型两种。

eleObj.children.forEach(child => {
    // 判断子元素是否是Element类型,是则递归,不是则创建文本节点
    child = (child instanceof Element) ? render(child) : document.createTextNode(child);
    el.appendChild(child);
});

真实DOM渲染到浏览器上

function renderDom(el, target) {
    target.appendChild(el);
}

 上诉步骤完成后,就可以将这几个方法导出去供其他使用即可

export {
    createElement,
    render,
    Element,
    renderDom
}

DOM Diff

Dom diff 则是通过JS层面的计算,返回一个patch对象,即补丁对象,在通过特定的操作解析patch对象,完成页面的重新渲染。

Patch 打补丁

当我们通过Diff算法获取补丁,然后通过patch打补丁来进行更新DOM,从而更新页面视图

DOM-diff  的过程:

  1. 用JS对象模拟DOM(虚拟DOM)
  2. 把此虚拟DOM转成真实DOM并插入页面中(render)
  3. 如果有事件发生修改了虚拟DOM,比较两棵虚拟DOM树的差异,得到差异对象(diff)
  4. 把差异对象应用到真正的DOM树上(patch)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值