TextArea 避免直接修改 prop,因为值会被覆盖

TextArea Avoid mutating a prop directly since the value will be overwritten

我知道类似的问题已经在Whosebug上处理过了。但是我无法从提议的解决方案中组合出一个解决方案。我很惭愧。

本质是这样的:我有一个组件,里面还有一个组件。 child组件-VClipboardTextField是一个ready-made配置的text-area。我无法从那里得到 input,并且当我尝试输入它时没有收到错误。

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "message"

代码 tabs-item.vue

<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 ></VClipboardTextField>
              <VClipboardTextField isReadOnly></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: '',
    }
  },
  methods: {
    sendRequest() {
      const message = {
        message: this.message,
        method: this.schema.state
      }
      this.$emit('sendRequest', message)
    },
    clearMessage() {
      this.message = ''
    },
    onChangeSchema(selectS) {
      console.log("get schema: ", selectS.state)
      this.schema = selectS

    }
  },

}
</script>

和childVClipboardTextField.vue

<template>
  <v-container>
    <v-tooltip bottom
               v-model="show">
      <template v-slot:activator="{ on, attrs }">
        <v-textarea
          v-model="message"
          :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>Tooltip</span>
    </v-tooltip>
  </v-container>
</template>

<script>
export default {
  name: 'VClipboardTextField',
  props: {
    isReadOnly: Boolean,
    message : { type :String, default: "msg"}
  },
  data() {
    return {
      show: false,
    //  messageLocal: 'Response!',
      iconIndex: 0,
    }
  },
  methods: {
    copyToBuffer() {
      console.log("this: ", this)
      navigator.clipboard.writeText(this.message);
      this.toolTipChange()
      setTimeout(() => this.toolTipChange(), 1000)
    },
    clearMessage() {
      this.message = ''
    },
    toolTipChange() {
      if (this.show)
        this.show = false
    }
  }
}
</script>

我很高兴看到一个代码示例,该示例将解释如何在没有拐杖的情况下正确解决此问题! 谢谢。

你不能修改组件中的props,如果需要message的初始值作为占位符(意味着开始时输入可能不为空),你可以存储数据在 message prop 到另一个数据变量并将其用作 v-modeltextarea。 如果 message 没有初始值,只需为 textarea 使用另一个数据变量并在 watcher 中为 message 发出更新.

代码中tabs-item.vue

<VClipboardTextField :message.sync="message"></VClipboardTextField>

和childVClipboardTextField.vue

<template>
  <v-container>
    <v-tooltip bottom
               v-model="show">
      <template v-slot:activator="{ on, attrs }">
        <v-textarea
          v-model="message_slug"
          :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>Tooltip</span>
    </v-tooltip>
  </v-container>
</template>

<script>
export default {
  name: 'VClipboardTextField',
  props: {
    isReadOnly: Boolean,
    message : { type :String, default: "msg"}
  },
  data() {
    return {
      show: false,
    //  messageLocal: 'Response!',
      iconIndex: 0,
      message_slug: '',
    }
  },
  watch: {
    message_slug(x) {
      this.$emit('update:message', x)
    }
  },
}
</script>

它会将值绑定到 message_slug 并在 parent 组件的值更改时更新 message

而不是每次都观察变化,你只能在有变化.

时发射

在你的选项卡中-item.vue

<VClipboardTextField v-model="message"></VClipboardTextField>

在您的 VClipboardTextField.vue 组件中,您可以接收 v-model 输入道具作为“VALUE" 属性并将其分配给本地数据 属性。这样你就可以操纵本地 属性 并仅在更改时发出!

<template>
  <v-container>
    <v-tooltip bottom v-model="show">
      <template v-slot:activator="{ on, attrs }">
        <v-textarea
          v-model="message"
          :append-outer-icon="'mdi-content-copy'"
          :readonly="isReadOnly"
          v-on="on"
          v-bind="attrs"
          auto-grow
          filled
          counter
          clear-icon="mdi-close-circle-outline"
          clearable
          label="Response message"
          type="text"
          @click:append-outer="copyToBuffer"
          @click:clear="clearMessage"
          @change="$emit('input', v)"
        ></v-textarea>
      </template>
      <span>Tooltip</span>
    </v-tooltip>
  </v-container>
</template>

<script>
export default {
  name: "VClipboardTextField",
  props: {
    isReadOnly: { type: Boolean },
    value: {
      type: String,
    },
  },
  data() {
    return {
      show: false,
      message: this.value,
    };
  },
};
</script>