Vue数据绑定简析小结(2)
首先初始化了一个 _watchers 数组,用来存放 watcher ,之后根据实例的 vm.$options ,相继调用 initProps 、 initMethods 、 initData 、 initComputed 和 initWatch 方法。
initProps
function initProps (vm, propsOptions) {
const propsData = vm.$options.propsData || {}
const props = vm._props = {}
// cache prop keys so that future props updates can iterate using Array
// instead of dynamic object key enumeration.
const keys = vm.$options._propKeys = []
const isRoot = !vm.$parent
// root instance props should be converted
if (!isRoot) {
toggleObserving(false)
}
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
...
defineReactive(props, key, value)
if (!(key in vm)) {
proxy(vm, '_props', key)
}
}
toggleObserving(true)
}
在这里, vm.$options.propsData 是通过父组件传给子组件实例的数据对象,如 <my-element :item="false"></my-element> 中的 {item: false} ,然后初始化 vm._props 和 vm.$options._propKeys 分别用来保存实例的 props 数据和 keys ,因为子组件中使用的是通过 proxy 引用的 _props 里的数据,而不是父组件传递的 propsData ,所以这里缓存了 _propKeys ,用来 updateChildComponent 时能更新 vm._props 。接着根据 isRoot 是否是根组件来判断是否需要调用 toggleObserving(false) ,这是一个全局的开关,来控制是否需要给对象添加 __ob__ 属性。这个相信大家都不陌生,一般的组件的 data 等数据都包含这个属性,这里先不深究,等之后和 defineReactive 时一起讲解。因为 props 是通过父传给子的数据,在父元素 initState 时已经把 __ob__ 添加上了,所以在不是实例化根组件时关闭了这个全局开关,待调用结束前在通过 toggleObserving(true) 开启。
之后是一个 for 循环,根据组件中定义的 propsOptions 对象来设置 vm._props ,这里的 propsOptions 就是我们常写的
export default {
...
props: {
item: {
type: Object,
default: () => ({})
}
}
}
循环体内,首先
const value = validateProp(key, propsOptions, propsData, vm)
validateProp 方法主要是校验数据是否符合我们定义的 type ,以及在 propsData 里未找到
