Bootstrap

构建一个支持精度、范围和负数的-Vue-数字输入框

分析并实现一个支持精度、范围和负数控制的数字输入框。

背景

在很多业务中,我们经常需要使用数字输入框,通常这些输入框会涉及到数字校验,比如限制输入范围、设置小数精度、是否允许负数等。每次写表单时,都需要重复定义这些校验规则,这不仅繁琐,而且无法满足灵活配置的需求。因此,我想到了能否将这些功能抽象成一个通用的、可复用的组件,避免每次都写重复的逻辑。

思路

直接限制输入,处理好输入的内容,就可以避免复杂的校验步骤了。有下面两种实现方式,我选择用组件的方式去实现,便于迁移。

  • 自定义指令
  • 自定义组件

设计与实现

设计

  • 精度控制:控制小数的位数,默认为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

;