学习总结:
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])
}
}
}