Vue子组件VClipboardTextField修改prop触发Avoid mutating a prop报错咨询
问题原因
你触发报错是因为直接在子组件内修改了message这个props属性,Vue不允许子组件直接变更父组件传递的props,所有props变更都需要由父组件执行,这是单向数据流的规范要求。同时你没有给子组件绑定父组件的变量,所以也拿不到子组件的输入内容。
修正后的代码
1. 子组件 VClipboardTextField.vue
主要修改点:
- 把直接绑定props的
v-model="message"替换为带get/set的计算属性,变更时触发事件通知父组件 - 把clearMessage方法里直接修改props的逻辑改为触发父组件更新事件
<template> <v-container> <v-tooltip bottom v-model="show"> <template v-slot:activator="{ on, attrs }"> <v-textarea v-model="localMessage" :append-outer-icon="'mdi-content-copy'" :readonly="isReadOnly" auto-grow filled counter clear-icon="mdi-close-circle-outline" clearable label="Response message" type="text" @click:append-outer="copyToBuffer" @click:clear="clearMessage" ></v-textarea> </template> <span>复制成功</span> </v-tooltip> </v-container> </template> <script> export default { name: 'VClipboardTextField', props: { isReadOnly: Boolean, message : { type :String, default: "msg"} }, data() { return { show: false, iconIndex: 0, } }, computed: { localMessage: { get() { return this.message }, set(val) { this.$emit('update:message', val) } } }, methods: { copyToBuffer() { console.log("this: ", this) navigator.clipboard.writeText(this.message); this.toolTipChange() setTimeout(() => this.toolTipChange(), 1000) }, clearMessage() { this.$emit('update:message', '') }, toolTipChange() { this.show = !this.show } } } </script>
2. 父组件 tabs-item.vue
主要修改点:
- 在data中新增对应子组件的绑定变量
- 给子组件添加
.sync修饰符绑定对应变量,即可同步获取子组件输入内容
<template> <v-container fluid> <v-row align="center"> <v-col cols="9"> <v-card flat> <v-card-text> <h1>Request</h1> <v-container> <v-textarea v-model="message" placeholder="Placeholder" label="Request" auto-grow clear-icon="mdi-close-circle-outline" clearable rows="10" row-height="5" @click:clear="clearMessage" ></v-textarea> <v-textarea v-model="response" placeholder="Placeholder" label="Request2" auto-grow counter rows="10" row-height="5" color="success" ></v-textarea> <!-- 绑定可编辑剪贴板输入框变量 --> <VClipboardTextField :message.sync="clipboardInputMsg"></VClipboardTextField> <!-- 绑定只读剪贴板输入框变量 --> <VClipboardTextField isReadOnly :message.sync="clipboardReadonlyMsg"></VClipboardTextField> </v-container> <v-row> <v-btn dark color="primary" elevation="12" justify="end" float-right @click="sendRequest" > Send Request </v-btn> </v-row> </v-card-text> </v-card> </v-col> <v-col cols="3"> <schema-selector @changeSchema="onChangeSchema"></schema-selector> </v-col> </v-row> </v-container> </template> <script> export default { name: 'tabs-item', props: ['response'], data() { return { schema: String, message: '', // 新增子组件绑定变量 clipboardInputMsg: '', clipboardReadonlyMsg: '' } }, methods: { sendRequest() { const message = { message: this.message, method: this.schema.state, // 这里可以直接取到子组件的输入内容 clipboardInput: this.clipboardInputMsg } this.$emit('sendRequest', message) }, clearMessage() { this.message = '' }, onChangeSchema(selectS) { console.log("get schema: ", selectS.state) this.schema = selectS } }, } </script>
实现说明
- 遵循Vue单向数据流规范,子组件所有数据变更都通过事件通知父组件修改,不会再触发props修改警告
- 父组件通过
.sync修饰符简化双向绑定逻辑,不需要额外监听事件即可同步子组件的输入内容 - 父组件可以直接通过data中定义的
clipboardInputMsg和clipboardReadonlyMsg拿到对应子组件的内容,不需要其他hack操作。
内容的提问来源于stack exchange,提问作者WBLord
相关产品推荐
相关产品推荐

