vue的虚拟dom

1,517 阅读2分钟

为什么需要虚拟dom

浏览器创建一个dom标签,实际上会创造一堆属性

例如,我创建了一个div对象,会有很多用不上的属性,一个看不出,但是如果每次都去新建-销毁,将会浪费大量的资源(这也是为什么不建议用JQ做dom操作,当然就我而言,修改属性可以使用JQ速度要快于通过vue),因此虚拟dom应运而生,VNode节点模拟真实DOM,可以对这颗抽象树进行创建节点、删除节点以及修改节点等操作,在这过程中都不需要操作真实DOM,Vue就使用了这样的抽象节点VNode,它是对真实DOM的一层抽象,而不依赖某个平台,它可以是浏览器平台,也可以是weex,甚至是node平台也可以对这样一棵抽象DOM树进行创建删除修改等操作,这也为前后端同构提供了可能。

// 在浏览器跑一下如下代码
var mydiv = document.createElement('div');
for(var k in mydiv ){
  console.log(k)
}

vue是如何使用虚拟dom

Vue通过数据绑定来修改视图,当某个数据被修改的时候,set方法会让闭包中的Dep调用notify通知所有订阅者Watcher,Watcher通过get方法执行vm._update(vm._render(), hydrating)。

对于这个div我们可以用一个简单的对象mydivVirtual代表它,它存储了对应dom的一些重要参数,在改变dom之前,会先比较相应虚拟dom的数据,如果需要改变,才会将改变应用到真实dom上。

如何判断是否需要改变--diff

在vue中有一个方法-patch

patch将新老VNode节点进行比对,然后将根据两者的比较结果进行最小单位地修改视图,而不是将整个视图根据新的VNode重绘。patch的核心在于diff算法,这套算法可以高效地比较virtual DOM的变更,得出变化以修改视图。

diff 算法是用来比较同层的节点进行比较,而非对树进行逐层判断

举例:

<!-- 之前 -->
<div>           <!-- 层级1 -->
  <p>            <!-- 层级2 -->
    <b> aoy </b>   <!-- 层级3 -->   
    <span>diff</Span>
  </P> 
</div>

<!-- 之后 -->
<div>            <!-- 层级1 -->
  <p>             <!-- 层级2 -->
      <b> aoy </b>        <!-- 层级3 -->
  </p>
  <span>diff</Span>
</div>

我们可能期望将< span>直接移动到< p>的后边,这是最优的操作。但是实际的diff操作是移除< p>里的< span>在创建一个新的< span>插到< p>的后边。 0因为新加的< span>在层级2,旧的在层级3,属于不同层级的比较。