VUE 官方文档上有很明确的解释:
单向数据流,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
所以如果破坏了单向数据流,当应用复杂时,debug 的成本会非常高!!
在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。
那如果修改了,vue 是如何监控到属性并给出警告的?
在 vue 底层,做了一个类似全局标记 Flag;它的实现原理,还是 Object.defineProperty()API;
proxy.js
const sharedPropertyDefinition = {
enumerable: true, // 可枚举
configurable: true // 是否可以被修改 被delete
};
export default function proxy(target, temp, key) {
sharedPropertyDefinition.get = function proxyGetter() {
return temp[key];
};
sharedPropertyDefinition.set = function proxySetter(val) {
temp[key] = val;
if (!window.isUpdatingChildComponent) {
console.error(`不可以直接更改: ${key}`);
}
window.isUpdatingChildComponent = false;
};
Object.defineProperty(target, key, sharedPropertyDefinition);
}
复制代码
window.isUpdatingChildComponent = false; 相当于一个 Flag; 只有当在父组件中修改传递给子组件的 Prop 值的时候,才会被赋值为 true; 在子组件 proxy.vue 中代理父组件传递的 Prop 值; 使用 this.$forceUpdate(); 强制更新; 这时候,触发代理中的 setter;提示不可以在子组件中直接修改父组件传递的 Prop 值的警告;
组件 proxy.vue:
<template>
<div>
info: {{ info }}
<input :value="info.name" @input="handleChange" />
</div>
</template>
<script>
import proxy from "./proxy";
export default {
props: {
info: Object
},
created() {
this.temp = { name: "" };
Object.keys(this.temp).forEach(key => {
proxy(this.info, this.temp, key);
});
},
methods: {
handleChange(e) {
this.info.name = e.target.value;
this.$forceUpdate();
//this.$emit("change", e.target.value);
}
}
};
</script>
复制代码
评论