学习总结:
1、 Vue 首次渲染的过程。
2、Vue 响应式原理。
Vue响应式的重点就是数据劫持/公布订阅模式,其余更多介绍查看Vue的官网的 深刻响应式原理一节,这里次要总结一下外部代码的实现。
- 先找找入口在哪里(src/core/instance/init.js)
initState(vm) --> initData(vm) --> observe()
//初始化Vue实例的状态,初始化了_props,methods,_data,computed,watch export function initState (vm: Component) { vm._watchers = [] const opts = vm.$options if (opts.props) initProps(vm, opts.props) if (opts.methods) initMethods(vm, opts.methods) if (opts.data) { initData(vm) // 看这里 } else { observe(vm._data = {}, true /* asRootData */) } if (opts.computed) initComputed(vm, opts.computed) if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch) } }
// 把 data 属性属性注入到Vue实例上 function initData(vm) { let data = vm.$options.data // 初始化 _data, 组件中 data 是函数,调用函数返回后果,否则间接返回data data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {} //... // 响应式解决 observe(data, true /* asRootData */) }
- 当初终于到正题了 observe(value) 响应式的入口
export function observe(alue: any, asRootData: ?boolean) { // 判断 value 是否是对象 if (!isObject(value) || value instanceof VNode) { return } let ob: Observer | void // 如果 value 有 __ob__(observer对象) 属性 完结(阐明曾经做过响应化解决) if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = value.__ob__ } else if ( shouldObserve && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue ) { // 创立一个 Observer 对象 ob = new Observer(value) } if (asRootData && ob) { ob.vmCount++ } return ob // 返回observer对象 }
3.观察者
export class Observer { value: any; // 察看对象 dep: Dep; // 依赖对象 vmCount: number; // 实例计数器 constructor (value: any) { this.value = value this.dep = new Dep() this.vmCount = 0 // 初始化实例的 vmCount 为0 def(value, '__ob__', this) // 将实例挂载到观察者对象的 __ob__ 属性 // 数组的响应式解决 if (Array.isArray(value)) { ... // 为数组中的每一个对象创立一个 observer 实例 this.observeArray(value) } else { // 遍历对象中的每一个属性,转换成 setter/getter this.walk(value) } } walk (obj: Object) { // 获取察看对象的每一属性 const keys = Object.keys(obj) // 遍历每一个属性,设置为响应式数据 for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]) } } // Vue重写了数组 push,popt,splice等有副作用的办法,当这些办法被调用的时候,会发送告诉; observeArray (items: Array<any>) { for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) } } }