[英]text input only takes one digit or multiple identical digits
I'm using Vue.js and would like to create a input field component that only takes positive integers (0 is fine too).我正在使用 Vue.js 并想创建一个只接受正整数的输入字段组件(0 也可以)。 I would like to avoid using regex to keep it human readable :)
我想避免使用正则表达式来保持人类可读:)
My consuming parent component passes in the current value and uses the shorthand sync directive我的消费父组件传入当前值并使用速记同步指令
<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>
The input component itself is just a basic text input (for better CSS styling)输入组件本身只是一个基本的文本输入(为了更好的 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>
Whenever the input changes I'm validating the incoming input for positive integers.每当输入更改时,我都会验证传入的输入是否为正整数。 If that validation fails I want to reset the current input field content (maybe there is a more userfriendly solution?)
如果验证失败,我想重置当前的输入字段内容(也许有更用户友好的解决方案?)
The input field itself only takes one digit or multiple identical digits.输入字段本身只需要一个数字或多个相同的数字。 So only these are possible:
所以只有这些是可能的:
but not:但不是:
Does someone know how to fix the component?有人知道如何修复组件吗?
Thanks in advance提前致谢
I'm still not entirely sure I understand the requirements but I think this is somewhere close to what you're looking for:我仍然不完全确定我了解要求,但我认为这与您要寻找的东西很接近:
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>
I've used $refs
instead of document.getElementById
to perform the reset.我使用
$refs
而不是document.getElementById
来执行重置。
To check the input is an integer I've simply converted it to an integer using parseInt
, then converted it back to a string and compared that to the original string.为了检查输入是一个整数,我只是使用
parseInt
将其转换为整数,然后将其转换回字符串并将其与原始字符串进行比较。
There are several edge cases that could cause problems.有几种边缘情况可能会导致问题。 A particularly obvious one is that the input can never be empty, which makes changing an existing value quite difficult.
一个特别明显的问题是输入永远不能为空,这使得更改现有值非常困难。 However, as far as I can tell, this does meet the requirements given in the question.
但是,据我所知,这确实符合问题中给出的要求。
Update:更新:
A few notes on number parsing.关于数字解析的一些注意事项。
Using Number(value)
will return NaN
if it can't parse the entire string.如果无法解析整个字符串,则使用
Number(value)
将返回NaN
。 There are some quirks with using Number
too.使用
Number
也有一些怪癖。 eg Try Number('123e4')
, Number('0x123')
or Number('0b11')
.例如,尝试
Number('123e4')
、 Number('0x123')
或Number('0b11')
。
Using parseInt(value, 10)
will parse as many characters as it can and then stop.使用
parseInt(value, 10)
将解析尽可能多的字符,然后停止。 parseInt
also has some quirks but by explicitly specifying a radix of 10
they mostly go away. parseInt
也有一些怪癖,但通过明确指定10
的基数,它们通常会消失。
If you try to parse '53....eeöööööö'
using parseInt
you'll get 53
.如果您尝试使用
parseInt
解析'53....eeöööööö'
您将得到53
。 This is an integer, so it'll pass a Number.isInteger
test.这是一个整数,因此它将通过
Number.isInteger
测试。
Personally I'd like to have used a RegExp to ensure the string only contains digits 0-9 before doing any further manipulation.我个人希望在进行任何进一步操作之前使用 RegExp 来确保字符串仅包含数字 0-9。 That quickly helps to eliminate a whole load of possible edge cases such that they wouldn't need any further consideration.
这很快有助于消除大量可能的边缘情况,这样它们就不需要任何进一步的考虑。 Something like
/^\\d*$/.test(value)
, or the converse !/\\D/.test(value)
.类似于
/^\\d*$/.test(value)
,或者相反的!/\\D/.test(value)
。
For the sake of completeness I tried to improve Skirtles answer.为了完整起见,我试图改进裙子的答案。 So the component consumer remains the same, only the input component changes a little bit.
所以组件消费者保持不变,只有输入组件发生了一点变化。 Now it's possible to leave the input empty but the value won't trigger an update then.
现在可以将输入留空,但该值不会触发更新。 Also the input field adds some visual styles based on the validation.
此外,输入字段根据验证添加了一些视觉样式。
<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>
Your problem is here:你的问题在这里:
const input = document.getElementById(this._uid);
input.value = this.value;
Use v-model
instead or try to replace code by this:改用
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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.