Vue2 虚拟DOM理解

161 阅读4分钟

虚拟DOM的本质

什么是DOM

  • DOM:简单来讲,就是一种数据格式。好比JSON。
    1. 正常开发网页,需要使用HTML,CSS,JavaScript。相信大家都知道这三种语言的作用
    2. 关键就是HTML,对于HTML文件,浏览器收到后,会有浏览器内部的渲染引擎去解析,转换
    3. 比如Chrom的渲染引擎Blink,他会解析HTML中的标签,文本各个节点,将整个HTML文件转换为一个DOM节点树
    4. 它既不是HTML语法,也不是JavaScript语法,它是一种用于表述HTML文件的数据模型,如下所示
// 这就是HTML转换后的DOM
Document
├── html
│   ├── head
│   │   ├── title
│   │   │   └── "My Webpage"
│   │   └── style
│   │       └── "body { background-color: #f0f0f0; } h1 { color: blue; }"
│   └── body
│       ├── h1
│       │   └── "Welcome to my webpage!"
│       ├── p
│       │   └── "This is a paragraph of text."
│       └── ul
│           ├── li
│           │   └── "Item 1"
  • DOM的作用:单纯的HTML文件,不支持Javascript控制,但是转换为DOM这种数据格式,既可以被渲染器解析渲染,又可以被Javascript引擎解析控制。

什么是虚拟DOM

  • 虚拟DOM:简单来讲,也是一种数据格式。它采用是JavaScript语言中的对象来表示

    1. 正常情况,我们JavaScript控制页面渲染,是通过浏览器提供的接口去操作DOM
    2. 关键就是DOM,对于DOM,我们通过浏览器提供的接口如,getElementById就可以获取到
    3. 获取到DOM节点后,我们可以使用JavaScript语言去操作。把它当成一个普通的Javascript对象就行
    4. 而虚拟DOM,是真正的JavaScript对象。
  • 虚拟DOM的作用:操作真实DOM,需要通过浏览器提供的接口去获取DOM,虚拟DOM,是由Javascript对象模拟的真实DOM。

    1. 在早期,前端页面很少有逻辑,基本是静态页面,那就不需要JavaScript获取控制页面的渲染
    2. 而随着Ajax的流行,许多逻辑被放到了前端页面,为了控制页面的动态渲染,就需要大量的操作浏览器提供的DOM接口。然而JavaScript执行逻辑是很快的,但是渲染器重新渲染则非常耗时。
    3. 稍微提一下,之所以说重新渲染非常耗时,是相对于js执行代码的速度来说的,每次重新渲染某个节点,除了节点本身外,其周围的节点也大概率会受影响。因此要避免重新渲染,或尽量减少对其他节点的影响
    4. 而使用虚拟DOM,我们就可以使用各种算法先分析这个虚拟DOM,将其需要重新渲染的部分尽量减少。分析完成后,再去操作真实的DOM,这样就能优化页面的渲染效率。
    5. 那虚拟DOM到底长什么样呢,其实就是一个普通对象,如下所示
{
  tag: 'div',
  children: [
    {
      tag: 'h1',
      children: [
        {
          text: '{{ title }}'
        }
      ]
    },
    {
      tag: 'p',
      children: [
        {
          text: '{{ content }}'
        }
      ]
    }
  ]
}

什么是VNode

  • 虚拟DOM是我们通过普通对象来模拟真实DOM的一种数据结构
  • 观察上述真实DOM的结构可以发现,DOM树是由不同的节点组成的。
  • VNode是描述DOM节点的JavaScript描述对象,与VDOM一样,只是描述的对象不同
  • VNode常见的类型与DOM节点基本对应,比如注释节点,文本节点,元素节点。
  • VNode是一个对象,不同类型的VNode只是对象的某些属性值不同,因此将VNode抽象成类。
  • 不同类型的VNode可以去继承通用的属性,或重写某些属性。VNode类的代码如下
export default class VNode { 
constructor (tag, data, children, text, elm, context, componentOptions, asyncFactory) { 
    this.tag = tag 
    this.data = data 
    this.children = children 
    this.text = text 
    this.elm = elm 
    this.ns = undefined 
    this.context = context 
    this.functionalContext = undefined 
    this.functionalOptions = undefined 
    this.functionalScopeId = undefined 
    this.key = data && data.key 
    this.componentOptions = componentOptions 
    this.componentInstance = undefined 
    this.parent = undefined 
    this.raw = false 
    this.isStatic = false 
    this.isRootInsert = true 
    this.isComment = false 
    this.isCloned = false 
    this.isOnce = false 
    this.asyncFactory = asyncFactory 
    this.asyncMeta = undefined 
    this.isAsyncPlaceholder = false 
   } 
    get child () { 
        return this.componentInstance 
    } 
}

什么是Patch

  • patch是通过vnode和vdom来分析需要重新渲染的部分,然后去通过DOMAPI操作真实的DOM。
  • 一般是采用vnode的方式来更新渲染,如果采用vdom,也就是更新整个页面,但其实我们可能只修改了某些节点,此时修改vnode是最小的成本。
  • 为了找出新旧vnode的不同,采用了diff算法来比较两个对象的属性。具体可看后续文章分析

总结

  • VNode是一个用于生成不同类型的vnode实例的类。
  • 不同vnode实例用来描述不同的真实DOM节点,他们之间的区别只是属性不同
  • Vue.js更新视图是通过将组件中的template解析为一个个的vnode实例,比较数据更新前后vnode的变化。将需要更新的部分,以最小开销渲染到页面