完整流程图

image.png

初始化与挂载

image.png

  • new Vue()字后,Vue会调用_init函数进行初始化,初始化生命周期、事件、propsmethodsdatacomputedwatch等。

  • 其中,通过Object.defineProperty设置settergetter函数,用于实现「响应式」以及「依赖收集」。

  • 初始化之后,调用$mount去挂载组件。

编译三部曲

image.png

  • Parse(解析):利用正则将模板转换成抽象语法树(AST);

  • optimize(标记静态节点做优化):标记静态节点(不需要绑定数据的节点),以后update的时候,Diff算法可以跳过静态节点;

  • generate(转成字符串):将抽象语法树(AST)转成字符串,供render去渲染Dom。

响应式

image.png

  • 利用Object.defineProperty设置data所返回对象,进行render function渲染时,读取data对象数据,出发getter函数;

  • data中的属性进行依赖收集,放到观察者(watcher)观察队列中;

  • 修改data内属性会出发setter函数,通知观察者数据变化,观察者调用update更新视图。

虚拟Dom

Render Function 会被转换成虚拟Dom—实际是一个js对象,从顶层Dom层层描述Dom,有tag,children,isStatic(是否为静态节点),isComment(是否为注释节点)等来描述。

Vue当中关于VNode类的定义。

  1. 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. devtoolsMeta: ?Object; // used to store functional render context for devtools
  27. fnScopeId: ?string; // functional scope id support
  28. constructor (
  29. tag?: string,
  30. data?: VNodeData,
  31. children?: ?Array<VNode>,
  32. text?: string,
  33. elm?: Node,
  34. context?: Component,
  35. componentOptions?: VNodeComponentOptions,
  36. asyncFactory?: Function
  37. ) {
  38. this.tag = tag
  39. this.data = data
  40. this.children = children
  41. this.text = text
  42. this.elm = elm
  43. this.ns = undefined
  44. this.context = context
  45. this.fnContext = undefined
  46. this.fnOptions = undefined
  47. this.fnScopeId = undefined
  48. this.key = data && data.key
  49. this.componentOptions = componentOptions
  50. this.componentInstance = undefined
  51. this.parent = undefined
  52. this.raw = false
  53. this.isStatic = false
  54. this.isRootInsert = true
  55. this.isComment = false
  56. this.isCloned = false
  57. this.isOnce = false
  58. this.asyncFactory = asyncFactory
  59. this.asyncMeta = undefined
  60. this.isAsyncPlaceholder = false
  61. }
  62. // DEPRECATED: alias for componentInstance for backwards compat.
  63. /* istanbul ignore next */
  64. get child (): Component | void {
  65. return this.componentInstance
  66. }
  67. }

更新视图

image.png

  • 数据变化后,执行render function可以得到一个新的VNode节点;
  • 得到新视图最简单粗暴的方法:直接解析新VNode节点,用innerHTML全部渲染到真实DOM;
  • update时,执行patch,传入新旧VNode,通过Diff算法算出差异,局部更新视图,做到最优化。