Vue 3 中的 Vue JS @change 和 @keydown 事件

Vue JS @change and @keydown events in Vue 3

我想弄清楚 keydownchange 事件如何在 Vue.js (Vue 3) 中协同工作。设置非常简单。我在一个组件中有一个文本输入,我希望能够在文本输入字段中输入一个数字。从那里,我希望能够使用箭头键(向上和向下)来增加或减少输入中的值。当输入失去焦点时,它应该触发@change然后更新模型。

我遇到的这个问题是,当我使用 @keydown 更新输入中的值时,它的行为方式与可打印字符的按键行为不同。更新 @keydown 上的值不会导致在控件失去焦点时触发 @change 事件。

如果有帮助,我在 playground 中设置了一个示例,但这是代码:

App.vue

<script>
import NumberInput from './NumberInput.vue'

export default {
  components: { 
    NumberInput
  },
  data() {
    return {
      number: 100
    }
  }
}
</script>

<template>
  <p>
    Model should only be updated when focus leaves the text box.
  </p>
  <p>
    This works fine when you type in a number and focus off the text box.
  </p>
  <p>
    However, when you <b>only</b> use the arrow keys to modify a value, the `@change` event doesn't fire.  
  </p>
  <br />
  <div style="padding:10px; border:1px solid #aaaaaa">
    <NumberInput v-model="number" />
    Number: {{ number }}
  </div>
</template>

NumberInput.vue

<script>
export default {
    props: ['modelValue'],
  data() {
    return {
        number: this.modelValue
    }
  },
  methods: {
    incrementOrDecrementNumber: function(e) {
      const isUpKey = (e.key === "ArrowUp");
            const isDownKey = (e.key === "ArrowDown");
        let x = parseInt(this.number, 10);
      if (x == NaN)
        x = 0;
      if (isUpKey || isDownKey) {
        if (isUpKey)
          x++;
        else
          x--;
        this.number = x;
        e.preventDefault();
      }
    },
    numberChanged: function(e) {
      this.$emit("update:modelValue", this.number);
    }
  }
}
</script>

<template>
  <div>
    Enter a number (press up or down to modify): <input type="text" v-model="number" @change="numberChanged($event);" @keydown="incrementOrDecrementNumber($event);" />
  </div>
</template>

是否可以在组件中更新 this.number 并让它在输入失去焦点时触发 @change 事件?

谢谢!

您 运行 遇到的问题不是由于“keydownchange 事件如何在 Vue.js 中协同工作”,实际上与此无关Vue.js 本身,而是 HTML 和 JavaScript 的基本潜在问题。如果用户通过直接与网页中的字段交互更改输入字段的数据,将在输入字段中触发更改事件,因为这会将元素的“脏”标志设置为 true.

在您的代码中,当用户的按键动作触发更改时,输入值正在内部通过JavaScript更改,这不会触发更改事件,无论是通过 Vue.js 还是通过普通 JavaScript.

进行更改

要触发更改事件,您可以通过特定方式更改输入值,例如根据 this answer 在输入元素上使用 setAttribute(value,...) 或直接调用更改事件。

在您自己的代码中,@blur="numberChanged($event)" 可以像我评论中指出的那样工作:

<input
    type="text"
    v-model="number"
    @change="numberChanged($event)"
    @blur="numberChanged($event)"
/>

或者您可以根据 Vue.js documentation 使输入值成为组件的“模型”。我还将输入类型设置为数字,以便本机提供输入 up-down 箭头键响应:

<script>
export default {
  props: ["modelValue"],
  emits: ["update:modelValue"],
  },
};
</script>

<template>
  <div>
    <p>
      Enter a number (press up or down to modify):
      <input
        type="number"
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"
      />
    </p>
  </div>
</template>