共计 3185 个字符,预计需要花费 8 分钟才能阅读完成。
以下是 Vue 结构申明外围代码,是跨平台共用的外围代码,为什么说跨平台共用呢,这里次要指的是不同平台(web 和 weex)在 vue.prototype 上还会丰盛本人的个性(属性和办法),如比拟重要的__patch__办法、以及平台特定的组件和指令。
import {initMixin} from './init'
import {stateMixin} from './state'
import {renderMixin} from './render'
import {eventsMixin} from './events'
import {lifecycleMixin} from './lifecycle'
import {warn} from '../util/index'
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
其中各种 Mixin 次要是丰盛原型链上的属性或办法:
initMixin: 申明 vue.prototype.init,前面会细看,见原型 init
stateMixin: 申明 vue.prototype.[$data | $props]属性,以及 $set、$delete、$watch 办法
eventsMixin: 申明 vue.prototype.[$on | $off | $once | $emit] 办法,让 vm 本身取得了事件的注册触发能力
lifecycleMixin: 申明 vue.prototype.[_update | $forceUpdate | $destroy] 办法
renderMixin: 申明 vue.prototype.[_render | $nextTick] 办法,以及一系列外部 helpers 工具函数,以(_字母)别名办法
切换到 Web 平台视角
先暂且只看 web 平台目录给 vue.prototype 上削减 [_patch_ | $mount] 办法,并且将平台特定指令和组件装置到结构 Vue.options 上。
原型 init
其中次要局部,一部分是:
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
另一部分是:
if (vm.$options.el) {vm.$mount(vm.$options.el)
}
其它蕴含 vue 的 options 的解析、合并及合并策略。
第一局部:
initLifecycle: 申明 vm 实例属性[$parent | $root | $children | $refs | _watcher | _inactive | _directInactive | _isMounted | _isDestroyed | _isBeingDestroyed],其中 $parent 会波及 parent 的解析和关系绑定,即在 parent 的 $children 中注册子 vm
initEvents: 申明 vm 实例属性[_events | _hasHookEvent],以及更新组件的事件 listeners 或者登记事件
initRender: 申明 vm 实例属性[_vnode | _staticTrees | $options | $vnode | $slots | $scopedSlots | _c | $createElement | $attrs | $listeners],其中 $attrs 和 $listeners 是响应式的属性,然而浅响应的。即在
defineReactive 申明时指定 shallow 为 true
看一看 defineReactive
- 肯定状况下放弃申明 key 原来的 getter 和 setter 的切面影响
- 通过 shallow 传入来管制对象该 key 的值是否须要持续纳入响应式治理
- 具体通过闭包 Dep 实例将该 key 纳入响应式零碎
通过 dep.depend 将 target:[Watcher]放入本人的 subs
看上去是调用 watcher 的 addDep 办法,并且该办法会判断是否曾经依赖该 dep
depend () {if (Dep.target) {Dep.target.addDep(this)
}
}
本质上最初还是调用了 dep 的 addSub 办法
addDep (dep: Dep) {
const id = dep.id
if (!this.newDepIds.has(id)) {this.newDepIds.add(id)
this.newDeps.push(dep)
if (!this.depIds.has(id)) {dep.addSub(this)
}
}
}
这样一来,dep 中有 watcher(通过 subs),watcher 中也有 dep(通过 newDepIds)
Dep 类
- Dep 类有一个动态属性 target,代表以后 watcher,全局惟一,每次只会有一个正在进行的 watcher,然而指标 watcher 是一个栈并且有配套的入栈和出栈操作,别离对应 pushTarget 和 popTarget,这种设计能够反对嵌套的调用和 watcher 解决。
- Dep 类通过 depend 办法建设和 watcher 的双向关联,并且 watcher 关联 dep 是通过 dep 的 addSub 办法,反之勾销关联是通过 dep 的 removeSub 办法
- Dep 类通过 notify 办法来告诉关联 wathcer[]来进行更新及动作
- Dep 代表响应式零碎中的被观察者
- 所有 Dep 实例对立进行 Uid 调配,即 Uid++
Watcher 类
- watcher 分为 renderWatcher 和 userWatcher,二者都会关联在 vm 的_watchers[]列表中,而且 renderWatcher 还会关联在 vm 的_watcher
- lazy-watcher 的 value 会通过 Watcher 的 evaluate 设置
- Dep 的 notify 触发 watcher 的 update 会辨别几种状况,一种是 lazy 的话会设置 dirty 的 flag,如果是 sync 的话会间接同步执行 getter 并且执行 cb 回调,其它状况会 queueWatcher
- Watcher 的 get 执行在执行初始化解析的 getter 之前会 pushTarget,这样在 getter 执行中若有相干的 dep.depend,则会关联以后 watcher 和 dep
- Watcher 监听 path 的解析算法是简略的 a.b.c 属性点宰割,但解析后的后果是一个闭包
- watcher 的回调执行只有在其 value 发生变化,或者 value 是对象,或者是 deep 时才会执行,具备肯定的惰性
- queueWatcher 的算法是若 watcher 队列还没有被 flush 则增加即可,若曾经被 flush 了然而还没有到它,则对刚 flush 的待执行队列进行查找替换,否则安顿至 nextTick 下一波队列
- Watcher 代表响应式零碎中的订阅者
- 所有 Watcher 实例对立进行 Uid 调配,即 Uid++
callHook: 执行相应的钩子函数及 vm 本身的钩子事件监听(如 vm.$on(‘hook:created’))
initInjections: 略
initState:
initProvide: 略
callHook: 同上