因为浏览器的标准把DOM设计的非常复杂,所以真正的DOM元素时非常庞大的,当我们频繁的做DOM的更新,会产生一定的性能问题。
而虚拟DOM就是用一个原生JS对象去描述一个DOM节点,所以它比创建一个DOM的代价要小很多。在Vue.js中,虚拟DOM是用Vnode这么一个class去描述的,它是定义在 src/core/vdom/vnode.js 中的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 export default class VNode { tag : string | void ; data: VNodeData | void ; children: ?Array <VNode>; text: string | void ; elm: Node | void ; ns: string | void ; context: Component | void ; key: string | number | void ; componentOptions: VNodeComponentOptions | void ; componentInstance: Component | void ; parent: VNode | void ; raw: boolean; isStatic: boolean; isRootInsert: boolean; isComment: boolean; isCloned: boolean; isOnce: boolean; asyncFactory: Function | void ; asyncMeta: Object | void ; isAsyncPlaceholder: boolean; ssrContext: Object | void ; fnContext: Component | void ; fnOptions: ?ComponentOptions; fnScopeId: ?string; constructor ( tag?: string, data?: VNodeData, children?: ?Array <VNode>, text?: string, elm?: Node, context?: Component, componentOptions?: VNodeComponentOptions, asyncFactory?: Function ) { this .tag = tag this .data = data this .children = children this .text = text this .elm = elm this .ns = undefined this .context = context this .fnContext = undefined this .fnOptions = undefined this .fnScopeId = 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 (): Component | void { return this .componentInstance } }
可以看到它包含了很多Vue.js的特性,其实它是借鉴了一个开源库snabbdom的实现,然后加入了一些vue.js特有的东西。
Vnode是对真实DOM的一种抽象描述,它的核心定义无非就是几个关键属性,标签名、数据、子节点、键值等,其他属性都用来扩展Vnode的灵活性以及实现一些特殊的feature。由于Vnode只是用来映射到真实DOM的渲染,不需要包含操作DOM的方法,所以它非常轻量和简单。
虚拟DOM除了它的数据结构的定义,映射到真实的DOM实际上要经历Vnode的create、diff、patch等过程。那么在 Vue.js 中,VNode 的 create 是通过之前提到的 createElement 方法创建的,我们接下来分析这部分的实现。