You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue Formulate数字输入限制小数位数异常问题求助

问题描述

需求:限制输入框仅允许小数位数不超过2位的数字(如10.12、10.1、10.00、10均合法,10.123非法)。基于vue-formulate实现时采用截取小数点后位数的方式处理,出现异常:

  • 输入10.11后,第一次输入2会被正常拦截;
  • 再次输入2时,输入框会显示10.112,超出限制;
  • 输入其他数字(如3)则不会出现该问题。

当前代码:

<FormulateInput
    name="height"
    type="number"
    step=".01"
    placeholder="0.0"
    v-model="height"
    :value="getHeightValue"
    :disabled="disableHeight"
    @input="updateField('height', $event)"
    min="0"
/>
updateField(field, value) {
      const numberOfDecimal = (field === 'height' || field === 'depth') ? 3 : 2
      this[field] = (value.indexOf(".") >= 0) ? (value.substr(0, value.indexOf(".")) + value.substr(value.indexOf("."), numberOfDecimal)) : value;
    },

原因分析

你的推测完全正确:第二次输入相同数字时updateField未触发,本质是vue-formulate的v-model同步逻辑问题:

  1. 第一次输入2后,updateField将值修正为10.11,输入框DOM值同步为该值;
  2. 再次输入2时,输入框DOM值短暂变为10.112,但由于修正后的模型值还是10.11,vue-formulate判断「模型值未变化」,因此不触发@input事件,修正逻辑不执行,非法值留在输入框;
  3. 输入不同数字时,模型值会产生变化,触发@input执行修正,因此无异常。

另外注意:代码中numberOfDecimal给height/depth设为3,和需求的「最多2位小数」逻辑冲突,是潜在问题。

解决方案

方案1:修正截取逻辑+强制同步输入框值

直接在修正模型值后,强制更新输入框DOM值,避免重复输入时的同步遗漏:

updateField(field, value) {
  // 按需求统一设置最多2位小数
  const maxDecimal = 2;
  let correctedValue = value;
  if (value?.indexOf(".") >= 0) {
    // substr第二个参数是长度,需+1(包含小数点本身)
    correctedValue = value.substr(0, value.indexOf(".")) + value.substr(value.indexOf("."), maxDecimal + 1);
  }
  // 强制赋值更新模型
  this[field] = correctedValue;
  // 强制同步输入框DOM值
  this.$nextTick(() => {
    const inputEl = document.querySelector(`[name="${field}"]`);
    if (inputEl) inputEl.value = correctedValue;
  });
}

方案2:改用vue-formulate自定义验证规则

利用组件原生验证能力,比手动截取更符合设计逻辑,也避免DOM操作:

  1. 全局/局部注册验证规则:
Vue.use(VueFormulate, {
  rules: {
    maxDecimal2: ({ value }) => {
      if (!value) return true;
      // 匹配最多2位小数的数字
      return /^\d+(\.\d{1,2})?$/.test(value.toString());
    }
  }
});
  1. 修改组件配置:
<FormulateInput
    name="height"
    type="text"  // 改用text类型,避免number类型自动格式化干扰
    placeholder="0.0"
    v-model="height"
    :disabled="disableHeight"
    min="0"
    validation="maxDecimal2"
    validation-message="请输入最多2位小数的数字"
/>

方案3:双事件监听+优化截取逻辑

同时监听@input和@change事件,确保所有输入场景都触发修正:

<FormulateInput
    name="height"
    type="number"
    step=".01"
    placeholder="0.0"
    v-model="height"
    :value="getHeightValue"
    :disabled="disableHeight"
    @input="updateField('height', $event)"
    @change="updateField('height', $event)"
    min="0"
/>

优化截取逻辑:

updateField(field, value) {
  const maxDecimal = 2;
  if (value?.indexOf(".") >= 0) {
    const [integerPart, decimalPart] = value.split(".");
    const trimmedDecimal = decimalPart.slice(0, maxDecimal);
    this[field] = `${integerPart}.${trimmedDecimal}`;
  } else {
    this[field] = value;
  }
}

关键注意点

  • 原代码中numberOfDecimal的取值与需求冲突,必须修正;
  • number类型输入框存在浏览器兼容性和自动格式化问题,追求精准控制时推荐用text类型配合正则验证;
  • 重复输入相同数字时,vue响应式系统可能认为值未变化,需通过强制同步DOM或多事件监听解决。

内容的提问来源于stack exchange,提问作者Serenity

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:36:41