Skip to content

前言

先了解下派发更新的流程

  1. dep.notify(),依次调用dep中watcher.update
  2. watcher.update() 会执行queueWatcher(this),将当前watcher添加到异步刷新队列中,每个watcher 都有一个watcher.id 在queueWatcher中会去掉重复的watcher,并且如果是第一个添加,将刷新队列flushSchedulerQueue的再添加nexttick()等待执行。
  3. flushSchedulerQueue中会依次调用当前队列中watcher.run(),watcher.run()关键的就是value = this.get()获取最新值,当然这个get不会触发依赖收集(没有Dep.target),同时会执行回调(watcher总有回调),如果是render-watcher,回调就是updateComponent(vm_.render())

vm_.render()

会生成一个vnode,分为两种场景,第一个是该组件无子组件的情况,全部是原始的html,第二个是带vue组件的场景。

  1. _render和我们在选项中写的render函数区别,关键在createElement()函数
  2. createElement(tag, options, children), 根据tag创建不同的vnode,区分为html vnode和组件vnode,组件vnode有两种(tag本身是构造函数或对象, tag是字符串能和组件注册的name 匹配的组件的),组件生成的vnode会添加构造函数和hook,tag会变成Vue-component-id-componentName。返回的是一个具有初始化选项的Vue类
  3. 代码中有两处createComponent, 一个是转换真实dom的时候,一个是创建组件vnode的时候(作者取名偷懒,这个地方实际应该取名为createComponentVnode)

vm._updata(vnode)

  1. update中逻辑单一,主要根据实例上是否存在vnode来走新建还是更新的流程,新建和更新都是走的patch 函数(),区别一参传入的是真实dom还是prevnode
  2. 走到createElm流程中,又执行了一次另一个createComponent(),如果是html的vnode,createComponent()不会返回,从而走到后续的创建的dom的流程,并将dom和当前实例绑定
  3. 如果是组件,执行vnode.data.hook.init(), init()中如果是已经存在的实例走prepatch更新,新建走createComponentInstanceForVnode()执行vnode.data.Ctor的new初始化,返回一个Vue的实例
  4. Vue实例执行$mount挂载方法,又会走Vue子组件的_update流程,依次迭代。最后将Vue实例挂载到真实的dom上。