深入浅出Vue.js读后总结-虚拟DOM

252 阅读4分钟

一、什么是虚拟DOM

web早期,不需要频繁的操作DOM,使用Jquery来开发就可以满足需求。随着时代的发展,DOM操作越来越频繁,如果用原来的办法的话程序中的状态很难管理,这就是命令式操作DOM的问题,而Vue是声明式操作DOM,我们只需要描述状态和DOM之间的关系就可以。

访问DOM是非常昂贵的,如果直接不关心状态变化,直接把DOM全删了,然后再重新生成一份DOM是非常消耗性能的,为了解决这个问题,各大框架都有自己的一套方案:Angular是脏检查,React是虚拟DOM,vue1是通过细粒度的绑定,vue2就采用了中等粒度的办法,引入虚拟DOM。

虚拟DOM其实就是通过状态生成一个虚拟节点数,然后使用虚拟节点树进行渲染,渲染之前,新生成的虚拟节点数会和上一次的进行对比,只渲染不同的部分

二、为什么要引入虚拟DOM

Angular和React是不知道哪些状态变了的,所有状态改变后就需要通过暴力对比,而vue不一样,状态变化后就知道哪个节点使用了这个状态,不需要对比,vue1就是这样实现的。

但vue1的粒度太细致,项目越大,依赖追踪的开销就越大,所有vue2使用了中等粒度的方案,引入了虚拟DOM,状态变化只通知到组件,组件内部再进行虚拟DOM渲染。

虚拟DOM在vue中所做的事就说提供vnode和对新旧两个vnode进行对比,并将对比结果进行DOM操作来更新视图。

三、什么是Vnode

vue中存在一个VNode类,用来实例化不同类型的vode实例(就说js中的一个对象),它描述了怎么去创建真实的DOM。

vode的类型包括:

(1)注释节点

(2)文本节点

(3)元素节点

(4)组件节点

(5)函数式节点

(6)克隆节点

四、patch

虚拟DOM的最核心部分就是patch,它将vnode渲染成真实的DOM,patch的过程其实就是创建节点、删除节点、修改节点的过程,当oldVnode和vnode不一样时,以vnode的标准来渲染视图。

1.新增节点

(1)发生在首次渲染中

(2)当vnode和oldVnode完全不是同一个节点的时候,vnode就是全新节点,oldVnode就是废弃节点。使用createElement和appendChild

2.删除节点:当vnode中不存在的节点都是废弃节点,要删除。使用removeNode

3.更新节点:两个节点是同一个节点,要对两个节点进行更细致的对比,然后对oldVnode在视图中对应的视图进行更新。更细致的对比后面单独说,很重要

更新节点详情

(1)先判断新旧两个节点是否是静态节点,是则跳过更新操作

(2)如果节点有文本属性,则看文本是否相同,不同直接setTextContent方法更新文本

(3)如果是元素节点的话,看是否有children属性(也就是子节点)

如果没有子节点就是空节点,则oldVnode对应视图中有什么删除什么

如果有子节点,就要对新旧两个虚拟节点的子节点进行一个详细对比并且更新(体现在updateChildren函数内):

updateChildren是深度优先,同层对比,其优化策略为:

有四种快捷查找方式:

(1)新前和旧前

(2)新后和旧后

(3)新后和旧前

(4)新前和旧后

新前:是newChildren中所有未处理的第一个节点 旧前:是oldChildren中所有未处理的第一个节点 新后:是newChildren中未处理的最后一个节点 旧后:是oldChildren中未处理的最后一个节点

这样可以很大程度的避免循环oldChildren来查找节点

优化后就是从两边向中间循环:利用oldStartIdx,oldEndIdx,newStartIdx,newEndIdx四个变量实现,每处理一个节点,就将下标向指定方向移动一个位置