【问题标题】:text input only takes one digit or multiple identical digits文本输入只需要一个数字或多个相同的数字
【发布时间】:2020-02-02 17:44:39
【问题描述】:

我正在使用 Vue.js,并且想创建一个只接受正整数的输入字段组件(0 也可以)。我想避免使用正则表达式来保持人类可读:)

我的消费父组件传入当前值并使用速记同步指令

<template>
  <div>
    <form>
      <positive-integer-input :value.sync="currentValue" />
    </form>
  </div>
</template>

<script>
import PositiveIntegerInput from "../components/PositiveIntegerInput.vue";

export default {
  components: {
    "positive-integer-input": PositiveIntegerInput
  },
  data() {
    return {
      currentValue: 0
    };
  }
};
</script> 

输入组件本身只是一个基本的文本输入(为了更好的 CSS 样式)

<template>
  <input :id="_uid" type="text" :value="value" @input="onInput" />
</template>

<script>
export default {
  props: {
    value: {
      type: Number,
      required: true
    }
  },
  methods: {
    onInput({ data }) {
      const inputNumber = Number(data);

      if (!Number.isInteger(inputNumber) || inputNumber < 0) {
        const input = document.getElementById(this._uid);
        input.value = this.value;
      } else {
        this.$emit("update:value", inputNumber);
      }
    }
  }
};
</script>

每当输入发生变化时,我都会验证输入输入是否为正整数。如果验证失败,我想重置当前输入字段内容(也许有更用户友好的解决方案?)

输入字段本身只需要一个数字或多个相同的数字。所以只有这些是可能的:

  • 3
  • 4
  • 333333
  • 4444

但不是:

  • 34

有人知道如何修复组件吗?

提前致谢

【问题讨论】:

  • 控制台有错误吗?
  • @question3r,我已经更新了我的答案。你能查到吗?
  • 不太清楚你在问什么。您想要的行为的哪些方面目前不起作用?您是否在问如何添加确保所有数字相同的条件?如果是这样,0 附近的期望值是多少?排除使用 RegExp 似乎有点武断。正确使用 RegExp 比其他方法更容易阅读。
  • @Nipun Jain 没有错误
  • @webprogrammer 我会在你的答案下面回答

标签: javascript html vue.js


【解决方案1】:

我仍然不能完全确定我是否理解这些要求,但我认为这与您正在寻找的内容很接近:

const PositiveIntegerInput = {
  template: `
    <input
      ref="input"
      type="text"
      :value="value"
      @input="onInput"
    >  
  `,

  props: {
    value: {
      type: Number,
      required: true
    }
  },

  methods: {
    onInput(ev) {
      const value = ev.target.value;
      const inputNumber = parseInt(value, 10);

      if (inputNumber >= 0 && String(inputNumber) === value) {
        this.$emit('update:value', inputNumber);
      } else {
        // Reset the input if validation failed
        this.$refs.input.value = this.value;
      }
    }
  }
};

new Vue({
  el: '#app',
  
  components: {
    PositiveIntegerInput
  },
  
  data () {
    return {
      currentValue: 0
    }
  }
})
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>

<div id="app">
  <div>
    <form>
      <positive-integer-input :value.sync="currentValue" />
    </form>
  </div>
</div>

我使用$refs 而不是document.getElementById 来执行重置。

要检查输入是否为整数,我只需使用parseInt 将其转换为整数,然后将其转换回字符串并将其与原始字符串进行比较。

有几种极端情况可能会导致问题。一个特别明显的问题是输入永远不能为空,这使得更改现有值非常困难。但是,据我所知,这确实符合问题中给出的要求。

更新:

关于数字解析的一些注意事项。

如果无法解析整个字符串,使用Number(value) 将返回NaN。使用Number 也有一些怪癖。例如试试Number('123e4')Number('0x123')Number('0b11')

使用parseInt(value, 10) 将解析尽可能多的字符,然后停止。 parseInt 也有一些怪癖,但通过明确指定 10 的基数,它们大多会消失。

如果您尝试使用parseInt 解析'53....eeöööööö',您将得到53。这是一个整数,所以它会通过Number.isInteger 测试。

我个人希望在进行任何进一步操作之前使用 RegExp 来确保字符串仅包含数字 0-9。这很快有助于消除大量可能的边缘情况,这样它们就不需要任何进一步的考虑。类似/^\d*$/.test(value),或者相反的!/\D/.test(value)

【讨论】:

  • 感谢您的回复。我检查了你的 sn-p 并将我的代码更新为你的 hatebin.com/hjofnpgbjw 当我在下面注释掉你的解决方案并使用我的解决方案时,代码无法正常工作,所以 53....eeöööööö 仍然有效......你知道为什么吗?跨度>
  • 因为您的解决方案仍然使-123 成为可能:)
  • @Question3r 确实如此。我已更新我的答案以防止出现减号。
  • 感谢您的更新。但是我还是想知道String(inputNumber) === valueNumber.isInteger(inputNumber)之间的区别..但是整数检查失败
  • @Question3r 我在末尾添加了进一步的更新,可能有助于澄清。
【解决方案2】:

为了完整起见,我尝试改进 Skirtles 的答案。所以组件消费者保持不变,只是输入组件发生了一点变化。现在可以将输入留空,但该值不会触发更新。此外,输入字段添加了一些基于验证的视觉样式。

<template>
  <input
    type="text"
    :value="value"
    @input="onInput"
    :class="[inputValueIsValid ? 'valid-input' : 'invalid-input']"
  />
</template>

<script>
export default {
  props: {
    value: {
      type: Number,
      required: true
    }
  },
  data() {
    return {
      digitsOnlyRegex: /^\d*$/,
      inputValueIsValid: false
    };
  },
  mounted() {
    this.validateInputValue(this.value);
  },
  methods: {
    onInput(inputEvent) {
      const currentInputValue = inputEvent.target.value;
      this.validateInputValue(currentInputValue);

      if (this.inputValueIsValid) {
        const inputNumber = parseInt(currentInputValue, 10);
        this.$emit("update:value", inputNumber);
      }
    },
    validateInputValue(currentInputValue) {
      const isNotEmpty = currentInputValue.toString().length > 0;
      const containsDigitsOnly = this.digitsOnlyRegex.test(currentInputValue);
      this.inputValueIsValid = isNotEmpty && containsDigitsOnly;
    }
  }
};
</script>

<style scoped>
.valid-input {
  background: green;
}

.invalid-input {
  background: red;
}
</style>

【讨论】:

    【解决方案3】:

    你的问题在这里:

    const input = document.getElementById(this._uid);
    input.value = this.value;
    

    改用v-model 或尝试用以下代码替换代码:

    <template>
      <input :id="_uid" type="text" :value="inputValue" @input="onInput($event.target.value, $event)" />
    </template>
    
    <script>
    export default {
      data(){
        return inputValue: 0,
      },
      props: {
        value: {
          type: Number,
          required: true
        }
      },
      created(){
        this.inputValue = this.value;
      },
      methods: {
        onInput(value, event) {
          const inputNumber = Number(value);
    
          if (!Number.isInteger(inputNumber) || inputNumber < 0) {
            this.inputValue = this.value;
          } else {
            this.$emit("update:value", inputNumber);
          }
        }
      }
    };
    </script>
    

    【讨论】:

    • 谢谢。但我不应该使用v-model,因为我使用的是prop-emit 事件流。第二个解决方案会完全打破这个流程,不是吗?
    • @Question3r,使用document.getElementById(this._uid); 绝对不是 vue 方式。
    • @Question3r,你在我的代码中仍然有this.$emit("update:value", inputNumber);,而不是使用v-model
    • 是的,我测试了你的例子。我可以粘贴我想要的每个字符,因此不再有保护
    • @Question3r,我不小心从输入中删除了onInput 方法。你能再检查一次我的代码吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多