You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 17:24:05