• Virtual DOM
    • 总结

    Virtual DOM

    Virtual DOM 这个概念相信大部分人都不会陌生,它产生的前提是浏览器中的 DOM 是很“昂贵"的,为了更直观的感受,我们可以简单的把一个简单的 div 元素的属性都打印出来,如图所示:
    Virtual DOM - 图1
    可以看到,真正的 DOM 元素是非常庞大的,因为浏览器的标准就把 DOM 设计的非常复杂。当我们频繁的去做 DOM 更新,会产生一定的性能问题。

    而 Virtual DOM 就是用一个原生的 JS 对象去描述一个 DOM 节点,所以它比创建一个 DOM 的代价要小很多。在 Vue.js 中,Virtual DOM 是用 VNode 这么一个 Class 去描述,它是定义在 src/core/vdom/vnode.js 中的。

    1. export default class VNode {
    2. tag: string | void;
    3. data: VNodeData | void;
    4. children: ?Array<VNode>;
    5. text: string | void;
    6. elm: Node | void;
    7. ns: string | void;
    8. context: Component | void; // rendered in this component's scope
    9. key: string | number | void;
    10. componentOptions: VNodeComponentOptions | void;
    11. componentInstance: Component | void; // component instance
    12. parent: VNode | void; // component placeholder node
    13. // strictly internal
    14. raw: boolean; // contains raw HTML? (server only)
    15. isStatic: boolean; // hoisted static node
    16. isRootInsert: boolean; // necessary for enter transition check
    17. isComment: boolean; // empty comment placeholder?
    18. isCloned: boolean; // is a cloned node?
    19. isOnce: boolean; // is a v-once node?
    20. asyncFactory: Function | void; // async component factory function
    21. asyncMeta: Object | void;
    22. isAsyncPlaceholder: boolean;
    23. ssrContext: Object | void;
    24. fnContext: Component | void; // real context vm for functional nodes
    25. fnOptions: ?ComponentOptions; // for SSR caching
    26. fnScopeId: ?string; // functional scope id support
    27. constructor (
    28. tag?: string,
    29. data?: VNodeData,
    30. children?: ?Array<VNode>,
    31. text?: string,
    32. elm?: Node,
    33. context?: Component,
    34. componentOptions?: VNodeComponentOptions,
    35. asyncFactory?: Function
    36. ) {
    37. this.tag = tag
    38. this.data = data
    39. this.children = children
    40. this.text = text
    41. this.elm = elm
    42. this.ns = undefined
    43. this.context = context
    44. this.fnContext = undefined
    45. this.fnOptions = undefined
    46. this.fnScopeId = undefined
    47. this.key = data && data.key
    48. this.componentOptions = componentOptions
    49. this.componentInstance = undefined
    50. this.parent = undefined
    51. this.raw = false
    52. this.isStatic = false
    53. this.isRootInsert = true
    54. this.isComment = false
    55. this.isCloned = false
    56. this.isOnce = false
    57. this.asyncFactory = asyncFactory
    58. this.asyncMeta = undefined
    59. this.isAsyncPlaceholder = false
    60. }
    61. // DEPRECATED: alias for componentInstance for backwards compat.
    62. /* istanbul ignore next */
    63. get child (): Component | void {
    64. return this.componentInstance
    65. }
    66. }

    可以看到 Vue.js 中的 Virtual DOM 的定义还是略微复杂一些的,因为它这里包含了很多 Vue.js 的特性。这里千万不要被这些茫茫多的属性吓到,实际上 Vue.js 中 Virtual DOM 是借鉴了一个开源库 snabbdom 的实现,然后加入了一些 Vue.js 特色的东西。我建议大家如果想深入了解 Vue.js 的 Virtual DOM 前不妨先阅读这个库的源码,因为它更加简单和纯粹。

    总结

    其实 VNode 是对真实 DOM 的一种抽象描述,它的核心定义无非就几个关键属性,标签名、数据、子节点、键值等,其它属性都是都是用来扩展 VNode 的灵活性以及实现一些特殊 feature 的。由于 VNode 只是用来映射到真实 DOM 的渲染,不需要包含操作 DOM 的方法,因此它是非常轻量和简单的。

    Virtual DOM 除了它的数据结构的定义,映射到真实的 DOM 实际上要经历 VNode 的 create、diff、patch 等过程。那么在 Vue.js 中,VNode 的 create 是通过之前提到的 createElement 方法创建的,我们接下来分析这部分的实现。

    原文: https://ustbhuangyi.github.io/vue-analysis/data-driven/virtual-dom.html