Vue.js: <input> 的@input 不适用于 v-for

Vue.js: @input for <input> not working with v-for

我正在创建自己的自定义 <input> Vue 组件。我正在做的是用户永远不会输入错误的输入类型。为此,我在每个输入处使用 regex.test()

这是我的 Vue 组件的代码,用于获取整数元素或整数数组:

<template>
    <div>
        <label>{{ label }}
            <template v-if="isArray">
                <input 
                    v-model="arr[i - 1]" 
                    @input="filterInput" 
                    :disabled="disableWhen" 
                    v-for="i in arraySize" 
                    :key="i">
                </input>
            </template>
            <template v-else>
                <input 
                    v-model="num" 
                    @input="filterInput" 
                    :disabled="disableWhen">
                </input>
            </template>
        </label>
        <el-button 
            type="success" 
            icon="el-icon-check" 
            circle 
            @click="confirm" 
            :disabled="disableWhen">
        </el-button>
    </div>
</template>

<script>
    export default {
        props: {
            label: String,
            nonNegative: Boolean,
            disableWhen: Boolean,
            isArray: Boolean,
            arraySize: Number
        },
        data() {
            return {
                num: '',
                arr: []
            }
        },
        methods: {
            filterInput() {
                if (this.nonNegative) {
                    if (!/^[0-9]*$/.test(this.num)) {
                        this.num = '';
                    }
                } else if (!/^(-)?[0-9]*$/.test(this.num)) {
                    this.num = '';
                }
            },
            confirm() {
                if (this.isArray) {
                    let validArrayInput = true;
                    for (let i = 0; i < this.arraySize; i++) {
                        if (!this.validInput(this.arr[i])) {
                            validArrayInput = false;
                        }
                    }
                    if (validArrayInput) {
                        this.$emit('confirm', this.arr);
                    }
                } else if (this.validInput(this.num)) {
                    this.$emit('confirm', this.num);
                }
            },
            validInput(x) {
                return (x !== '' && x !== '-' && typeof x !== "undefined");
            }
        }
    }
</script>

代码在 isArray = false 时正常工作,即对于整数元素。但是方法filterInputisArray = true时是永远不会被调用的,对于错误的输入也没有限制。有什么问题?

filterInput 对于两种类型的输入都可以正常调用,但它仅尝试操纵 num,它不会更改 arr.

这是我尝试实现的:

const MyInput = {
  template: `
    <div>
      <label>{{ label }}
        <template v-if="isArray">
          <input 
            v-for="i in arraySize" 
            v-model="arr[i - 1]" 
            :disabled="disableWhen" 
            :key="i"
            @input="filterInput" 
          >
        </template>
        <template v-else>
          <input 
            v-model="num" 
            :disabled="disableWhen"
            @input="filterInput"
          >
        </template>
      </label>
    </div>  
  `,

  props: {
    label: String,
    nonNegative: Boolean,
    disableWhen: Boolean,
    isArray: Boolean,
    arraySize: Number
  },
  
  data() {
    return {
      arr: []
    }
  },
  
  computed: {
    num: {
      get () {
        return this.arr[0]
      },
      
      set (num) {
        this.arr[0] = num
      }
    }
  },
  
  methods: {
    filterInput() {
      const arr = this.arr
      const re = this.nonNegative ? /^\d*$/ : /^-?\d*$/
      
      for (let index = 0; index < arr.length; ++index) {
        if (!re.test(arr[index])) {
          this.$set(arr, index, '')
        }
      }
    }
  }
}

new Vue({
  el: '#app',
  
  components: {
    MyInput
  }
})
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>

<div id="app">
  <my-input label="Single"></my-input>
  <br>
  <my-input label="Multiple" is-array :array-size="3"></my-input>
</div>

一些注意事项:

  1. 我已将 num 更改为由 arr[0] 支持的计算 属性。这简化了过滤逻辑,因为它只需要为两种类型的输入考虑 arr。它可以进一步简化,例如该模板实际上并不需要处理两种情况,它可以像对待多值一样对待单值,但 array-size 为 1。只有发出的值(不包含在我的代码中)才真正需要对于单值情况有不同的行为。稍加重构 num 可能会被完全删除。
  2. 实现是有状态的。如果您想从外部传入值,您将 运行 陷入困境。
  3. 与其将值设置为 '',我建议使用 replace 删除不允许的字符。我没有在我的代码中进行此更改,我想保留原始示例中的行为。
  4. 结束 </input> 标签无效,我已将其删除。
  5. 我试图删除的 filterInput 方法中有很多重复项。它现在检查 arr 数组中的所有条目。似乎没有必要针对已更改的特定输入。
  6. this.$set 用于按索引更新数组,否则反应系统将无法检测到(操作数组的标准警告)。