虚拟dom_虚拟DOM浅析

本文围绕虚拟DOM展开,介绍了其相关知识。先阐述了操作DOM慢的原因是频繁操作会引发页面重绘和重排,而虚拟DOM是用js创建的DOM,通过对比新旧DOM树差异,触发一次重绘完成页面更新,提高了性能,还提及了实现虚拟DOM的方法。

ae9a923dd6b2e1bd1799f978da90d35b.png

虚拟DOM

主要了解一下虚拟DOM,他为什么存在以及解决了什么问题,通过什么方式解决的。

什么是虚拟 DOM 以及他的作用

  • 什么是 DOM

在 MDN 的文档中,DOM 的定义是:

文档对象模型 (DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。

其中还有一个重要的概念:

DOM是web页面的完全的面向对象表述,它能够使用如 JavaScript等脚本语言进行修改。

这可以理解为:DOM 对象本身也是一个 js 对象,我们可以通过 js 对 DOM 进行操作。

  • 为什么操作 DOM 会慢

我们每一次使用 js 操作 DOM,或者 DOM 每一次细微的改变,都会引发页面的重绘(paint)和重排(layout);

当页面进行大量的频繁的 DOM 操作的时候,重绘和重排的也就被频繁触发,从而导致变慢。

  • 什么是虚拟 DOM

既然 DOM 树可以用 js 对象表示,那么反过来,我们也可以用 js 对象表示的树结构来构建一棵真正的 DOM 树。

虚拟 DOM 就是用 js 创建出来的 DOM。

  • 为什么虚拟 DOM 可以提高性能表现

频繁地操作 DOM 的触发页面多次渲染,影响性能。

但是使用虚拟 DOM,我们只需要通过对比新的 DOM 树和旧的 DOM 树的不同之处,然后针对差异修改 js 对象,最后把 js 对象所生成的 DOM 树插入到页面中,重新渲染页面,更新视图。

这样虚拟 DOM 就通过触发一次重绘,完成页面的更新,对比于 DOM 的多次重绘,性能表现明显地提高了。


如何实现虚拟 DOM

使用 js 创建一个虚拟 DOM 节点:

class VNode  {
    constructor(tag,children,text){
        this.tag = tag
        this.children = children
        this.text = text
    }
    render(){
        if(this.tag === '#text'){
            return document.createTextNode(this.text)
        }
        let el = document.createElement(this.tag)
        this.children.map((vchild) =>{
            el.appendChild(vchild.render())
        })
        return el
    }
}
function createNode(tag,children,text){
    if(typeof children === 'string'){
        text = children
        children = []
    }
    return new VNode(tag,children,text)

}
let vNodes = createNode('div', [
    createNode('p', [
        createNode('span', [ createNode('#text', 'xiedaimala.com') ] )
        ]
    ),
    createNode('span', [
        createNode('#text',  'jirengu.com')
        ])
    ]
)
console.log(vNodes.render())    // 返回了一个 DOM 节点

将节点挂载到页面某个元素上:

<div id="app"></div>

<script>
    let root = document.querySelector('#app)
    root.appendChild(vNodes.render())
</script>

更新虚拟 DOM (diff):

function patchElement(parent, newVNode, oldVNode, index = 0) {
  if(!oldVNode) {
    parent.appendChild(newVNode.render())
  } else if(!newVNode) {
    parent.removeChild(parent.childNodes[index])
  } else if(newVNode.tag !== oldVNode.tag || newVNode.text !== oldVNode.text) {
    parent.replaceChild(newVNode.render(), parent.childNodes[index])
  }  else {
    for(let i = 0; i < newVNode.children.length || i < oldVNode.children.length; i++) {
      patchElement(parent.childNodes[index], newVNode.children[i], oldVNode.children[i], i)
    }
  }
}
let vNodes1 = v('div', [
      v('p', [
        v('span', [ v('#text', 'xiedaimala.com') ] )
        ]
      ),
      v('span', [
        v('#text',  'jirengu.com')
        ])
    ]
  )

let vNodes2 = v('div', [
      v('p', [
        v('span', [
          v('#text', 'xiedaimala.com')
          ] )
        ]
      ),
      v('span', [
        v('#text',  'jirengu.coms'),
        v('#text',  'ruoyu')
        ])
    ]
  )
let root = document.querySelector('#app')
patchElement(root, vNodes1)

参考:

如何理解虚拟DOM?

MDN

虚拟DOM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值