分析并实现一个支持精度、范围和负数控制的数字输入框。
背景
在很多业务中,我们经常需要使用数字输入框,通常这些输入框会涉及到数字校验,比如限制输入范围、设置小数精度、是否允许负数等。每次写表单时,都需要重复定义这些校验规则,这不仅繁琐,而且无法满足灵活配置的需求。因此,我想到了能否将这些功能抽象成一个通用的、可复用的组件,避免每次都写重复的逻辑。
思路
直接限制输入,处理好输入的内容,就可以避免复杂的校验步骤了。有下面两种实现方式,我选择用组件的方式去实现,便于迁移。
- 自定义指令
- 自定义组件
设计与实现
设计
- 精度控制:控制小数的位数,默认为0,即整数
- 范围控制:配置最大值和最小值
- 负数输入:是否支持负数
实现
借用 element-UI
中的 el-input
组件实现。
需要特别注意的是:
- 必须先处理负号
- 如果小数点位数为 0 ,需要去掉小数点字符
<template>
<el-input
v-model="localValue"
@input="handleInput"
:placeholder="placeholder"
:clearable="clearable"
/>
</template>
<script>
export default {
name: 'NumberInput',
props: {
value: {
type: [Number, String],
default: null
},
min: {
type: Number,
default: -Infinity
},
max: {
type: Number,
default: Infinity
},
/**
* 小数点后保留的位数
*/
precision: {
type: Number,
default: 0
},
/**
* 是否允许输入负数
*/
allowNegative: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: '请输入数字'
},
clearable: {
type: Boolean,
default: true
}
},
data() {
return {
localValue: this.value || ''
}
},
watch: {
value(newValue) {
if (newValue !== this.localValue) {
this.localValue = newValue
}
},
localValue(newValue) {
this.$emit('input', newValue)
}
},
methods: {
handleInput() {
let value = this.localValue
// 如果允许负数,先处理负号
const isNegative = value.startsWith('-')
if (isNegative && !this.allowNegative) {
value = value.replace('-', '') // 如果不允许负数,去掉负号
}
// 如果 precision 为 0,则禁止输入小数点
if (this.precision === 0) {
value = value.replace(/\./g, '') // 禁止输入小数点
}
// 格式化为最多 `precision` 位小数
const decimalRegex = `^\\D*(\\d*(?:\\.\\d{0,${this.precision}})?).*`
value = value.replace(new RegExp(decimalRegex), '$1')
// 如果之前是负数,重新加上负号
if (isNegative && this.allowNegative) {
value = `-${value}`
}
// 限制最大值和最小值
if (parseFloat(value) < this.min) {
value = String(this.min)
} else if (parseFloat(value) > this.max) {
value = String(this.max)
}
// 更新本地值
this.localValue = value
}
}
}
</script>
<style scoped>
</style>
Q&A
为什么不用 el-input-number
- 默认值问题:当设置了min="0"时,会有默认值0。
- 负数输入限制:不支持
- 精度控制:只支持步长,不支持小数点精度控制
使用
<number-input
v-model="amount"
:min="0"
:max="9999"
:precision="2"
:allowNegative="true"
placeholder="请输入金额"
/>
参考
无。
首发地址:http://blog.xchive.top/2025/building-vue-number-input.html