浅谈虚拟DOM

298 阅读3分钟

什么是虚拟DOM?

虚拟DOM其实就是一个普通的JavaScript对象,包含了tag,props,children三个属性。

<div id="app">
  <p class="text">hello world!!!</p>
</div>

上面的 HTML 转换为虚拟 DOM 如下:

{
  tag: 'div',
  props: {
    id: 'app'
  },
  chidren: [
    {
      tag: 'p',
      props: {
        className: 'text'
      },
      chidren: [
        'hello world!!!'
      ]
    }
  ]
}

该对象就是我们常说的虚拟 DOM 了,因为 DOM 是树形结构,所以使用 JavaScript 对象就能很简单的表示。

为什么需要虚拟DOM?

已经有了DOM了,为什么还需要再引入一个新概念。

为各位几个问题?

「频繁操作DOM不烦吗?」

「频繁操作DOM对网页性能好吗?」

「使用DOM能实现跨平台开发吗?」

如果你在思考上面三个问题之后领悟到了直接通过操作DOM进行开发确实不容易,那么你离理解虚拟DOM又进了一部。

虚拟DOM的出现就是为了解决但不限于以上三个问题。

具体是怎么解决的呢?

改善大规模操作DOM的性能

虚拟DOM可以将多次操作合并为一次操作。(React的setState被设计成异步函数的初衷)

举例:加入我们要向页面中添加1000个div,在不使用vue和react的情况下只能一次一次的添加,而虚拟DOM可以将这1000个节点放在一个数组里,一次性的添加,减少了DOM的操作次数.

缩小DOM操作的范围

虚拟DOM借助DOM diff 可以将多余的操作省掉,只操作那些已经改变的DOM元素

举例,假如页面有990个节点,我们需要再添加10个节点,可是此时我们的数据中原来的和现在的节点放在了一起,此时虚拟DOM可以利用虚拟diff帮我们区分出新老节点,并只操作新的改变了的节点,缩小DOM操作范围。

能以较低成本实现跨平台开发

虚拟DOM不仅可以变成DOM,还可以变成小程序,iOS应用,安卓应用,因为虚拟DOM实际上是一个JS对象。

规避XSS风险

虚拟DOM内部确保了字符转义,因此可以避免XSS跨站脚本攻击,。

虚拟DOM实现原理

因为本人没有看过react源码,所以这里只是简单的阐述从虚拟DOM变成DOM的流程。

我们在实现一个React组件时可以选择两种编码方式,第一种是使用JSX编写:

class Hello extends Component {
  render() {
    return <div>Hello ConardLi</div>;
  }
}

第二种是直接使用React.createElement编写:

class Hello extends Component {
  render() {
    return React.createElement('div'null`Hello ConardLi`);
  }
}

实际上,上面两种写法是等价的,JSX只是为 React.createElement(component, props, ...children)方法提供的语法糖。也就是说所有的JSX代码最后都会转换成React.createElement(...),Babel帮助我们完成了这个转换的过程。 如下面的JSX

<div>
  <img src="avatar.png" className="profile" />
  <Hello />
</div>;

将会被Babel转换为

React.createElement("div", null, React.createElement("img", {
  src"avatar.png",
  className"profile"
}), React.createElement(Hello, null));

注意,babel在编译时会判断JSX中组件的首字母,当首字母为小写时,其被认定为原生DOM标签,createElement的第一个变量被编译为字符串;当首字母为大写时,其被认定为自定义组件,createElement的第一个变量被编译为对象;

下面我们来看看虚拟DOM的真实模样,将下面的JSX代码在控制台打印出来:

<div className="title">
      <span>Hello ConardLi</span>
      <ul>
        <li>苹果</li>
        <li>橘子</li>
      </ul>
</div>

而ReactElement最终形成的树结构就是Virtual DOM; 整体的转换过程如下:

参考

【React深入】深入分析虚拟DOM的渲染原理和特性