结论
1、props传值基本类型,在父子组件中,数据都是响应式的。在子组件中改变props属性的值,不会影响父组件。父组件中的改变会影响子组件。
2、props传值引用类型(如对象),在父组件中,会对该对象的所有属性进行拦截,而在子组件中,只会拦截最上层的属性。所以如果在子组件中修改对象的属性,父组件中的值会更新。父组件中的改变同样会影响子组件。但是如果直接替换掉整个对象,则父组件中的数据不会发生改变,如果直接替换整个对象,vue会抛出错误Avoid mutating a prop directly
3、在父组件中改变对应的data,子组件中的值也会改变。之所以要在子组件中再对props的数据用watch进行监听,是需要在数据变化时做一些操作。不如如果props中的值是在echarts中使用的话,数据改变不会自动刷新图表,所以需要监听,这样就知道什么去刷新图表。
过程描述
在created函数调用之前,调用了initProps方法,该方法会遍历vm.$options.propsData对象,然后使用Object.defineProperty拦截所有的key。
第一步 两个关键的步骤,
1、拦截属性的get/set,调用 defineReactive$$1传了四个参数,所以才不会拦截对象的属性。详见第二步的方法。
2、使用proxy进行访问转接,所以我们能使用this.xx直接访问到this. vm._props.xx
function initProps (vm, propsOptions) {
var propsData = vm.$options.propsData || {};
var props = vm._props = {};
defineReactive$$1(props, key, value, function () {
if (!isRoot && !isUpdatingChildComponent) {
//错误提示代码
}
});
}
if (!(key in vm)) {
proxy(vm, "_props", key);
}
};
}
第二步
function defineReactive$$1 (
obj,
key,
val,
customSetter,
shallow
) {
var dep = new Dep();
var property = Object.getOwnPropertyDescriptor(obj, key);
//在initData和initProps方法中,调用defineReactive$$1方法传的参数不一样
//从而影响val值,最终影响是否调用observe(val)方法
//在initData中传入的参数是2个,会调用observe(val)方法,从而实现对象的深度监听
//在initProp中,不会调用observe(val),所以不会监听对象的属性
if ((!getter || setter) && arguments.length === 2) {
val = obj[key];
}
var childOb = !shallow && observe(val);
Object.defineProperty(obj, key, {
get: function reactiveGetter () {
if (Dep.target) {
dep.depend();
//props属性队形的childOb为false
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},
set: function reactiveSetter (newVal) {
//省略其他代码
dep.notify();
}
});
}










网友评论