使用v-bind.sync绑定prop触发Avoid mutation props directly警告如何解决
问题原因
你收到警告的核心原因是子组件直接将v-model绑定到了props属性上:v-model默认会直接修改绑定的变量值,这违反了Vue单向数据流的规范,你后续添加的keyup emit事件是在prop被修改之后才触发,所以警告依然会抛出。
另外你的示例代码父组件存在嵌套层级错误:当前v-bind.sync="data"绑定的是外层{data: {name: 'Oslo name', access: 'admin'}}对象,只会向子组件传递一个名为data的prop,子组件的name和access无法正确接收值,实际使用时需要修改为v-bind.sync="data.data"才能正确展开属性。
优化方案
方案1:计算属性get/set实现(最规范,推荐)
无需修改父组件逻辑,完全适配你当前的v-bind.sync用法,也符合Vue单向数据流规范:
<!-- 子组件 Oslo.vue --> <template> <div> <input type="text" v-model="localName" /> <input type="text" v-model="localAccess" /> </div> </template> <script> export default { props: { name: String, access: String }, name: 'Oslo', computed: { localName: { get() { return this.name }, set(val) { this.$emit('update:name', val) } }, localAccess: { get() { return this.access }, set(val) { this.$emit('update:access', val) } } } } </script>
如果需要双向绑定的prop数量很多,可以抽一个公共工具函数批量生成计算属性,减少重复代码:
// 公共工具方法,可全局复用 function createSyncComputed(props) { return props.reduce((result, propName) => { result[`local${propName[0].toUpperCase() + propName.slice(1)}`] = { get() { return this[propName] }, set(val) { this.$emit(`update:${propName}`, val) } } return result }, {}) } // 子组件内直接调用 export default { props: { name: String, access: String, // 其他大量prop }, computed: { // 传入需要生成双向绑定的prop名称数组即可 ...createSyncComputed(['name', 'access']) } }
方案2:传递整个对象(适合大量字段的内部业务组件)
如果字段数量非常多,不想写大量emit事件,可以直接把整个数据对象作为单个prop传递,利用对象是引用类型的特性,直接修改内部属性不会触发prop修改警告:
<!-- 父组件修改绑定方式 --> <template> <div> <oslo :formData="data.data" /> </div> </template>
<!-- 子组件直接绑定对象内部属性 --> <template> <div> <input type="text" v-model="formData.name" /> <input type="text" v-model="formData.access" /> </div> </template> <script> export default { props: { formData: Object }, name: 'Oslo', } </script>
该方式代码量最小,仅建议在内部业务组件、父子组件逻辑耦合度较高的场景使用。
不推荐的静默警告方案
如果确实不想修改现有代码,也可以通过配置屏蔽警告,但该方式会隐藏其他潜在的prop修改问题,非常不推荐:
// 项目入口main.js中添加,会屏蔽所有Vue的警告提示 Vue.config.silent = true
内容的提问来源于stack exchange,提问作者Kiran Maniya
相关产品推荐
相关产品推荐

