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

Angular 4两位小数数字输入指令问题及修复咨询

修复方案:允许先输入小数点并在前方输入数字

我看了你的OnlyNumber指令,问题出在当输入框值为.时,parseFloat(e.target.value)得到NaN,加上原有的minValue判断逻辑可能错误阻止了数字输入,同时光标位置的处理也没考虑到在小数点前输入的场景。下面是修复后的完整代码,以及关键修改点说明:

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({ selector: '[OnlyNumber]' })
export class OnlyNumber {
  elemRef: ElementRef;

  constructor(private el: ElementRef) { 
    this.elemRef = el;
  }

  @Input() OnlyNumber: boolean;
  @Input() DecimalPlaces: string;
  @Input() minValue: string;
  @Input() maxValue: string;

  @HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) {
    if (!this.OnlyNumber) return;

    // 允许控制键和导航键
    const allowedKeys = [46, 8, 9, 27, 13, 110, 190];
    if (allowedKeys.includes(event.keyCode) ||
        // Ctrl+A/C/X 快捷键
        (event.keyCode === 65 && event.ctrlKey) ||
        (event.keyCode === 67 && event.ctrlKey) ||
        (event.keyCode === 88 && event.ctrlKey) ||
        // 方向键、home/end
        (event.keyCode >= 35 && event.keyCode <= 39)) {
      return;
    }

    // 阻止非数字键(数字小键盘除外)
    if ((event.shiftKey || (event.keyCode < 48 || event.keyCode > 57)) && 
        (event.keyCode < 96 || event.keyCode > 105)) {
      event.preventDefault();
    }
  }

  @HostListener('keypress', ['$event']) onKeyPress(event: any) {
    if (!this.OnlyNumber) return;

    const inputValue = this.elemRef.nativeElement.value;
    const currentCursorPos = this.elemRef.nativeElement.selectionStart;
    const isCursorBeforeDot = inputValue.includes('.') && currentCursorPos <= inputValue.indexOf('.');
    const newChar = event.key;

    // 处理minValue判断:兼容空输入或仅小数点的场景
    if (this.minValue) {
      const min = parseFloat(this.minValue);
      let tempValue: number;

      if (inputValue === '' || inputValue === '.') {
        tempValue = parseFloat(newChar + inputValue);
      } else {
        tempValue = parseFloat(inputValue);
      }

      if (!isNaN(tempValue) && tempValue < min) {
        event.preventDefault();
      }
    }

    // 处理maxValue判断:根据光标位置计算输入后的临时值
    if (this.maxValue) {
      const max = parseFloat(this.maxValue);
      let tempValue: number;

      if (inputValue === '.' || inputValue === '') {
        tempValue = parseFloat(newChar + inputValue);
      } else if (isCursorBeforeDot) {
        tempValue = parseFloat(inputValue.slice(0, currentCursorPos) + newChar + inputValue.slice(currentCursorPos));
      } else {
        tempValue = parseFloat(inputValue + newChar);
      }

      if (!isNaN(tempValue) && tempValue > max) {
        event.preventDefault();
      }
    }

    // 处理小数位数限制:仅光标在小数点后时生效
    if (this.DecimalPlaces) {
      const decimalPlaces = parseInt(this.DecimalPlaces);
      const dotCount = (inputValue.match(/\./g) || []).length;
      const decimalPartLength = inputValue.split('.')[1]?.length || 0;

      // 阻止输入多个小数点
      if (dotCount >= 1 && newChar === '.') {
        event.preventDefault();
        return;
      }

      // 只有光标在小数点后时,才限制小数位数
      if (!isCursorBeforeDot && dotCount === 1) {
        const newDecimalLength = decimalPartLength + (/\d/.test(newChar) ? 1 : 0);
        if (newDecimalLength > decimalPlaces) {
          event.preventDefault();
        }
      }
    }
  }

  // 可选优化:失去焦点时自动补全小数点前的0(比如`.`变成`0.`)
  @HostListener('blur') onBlur() {
    const inputValue = this.elemRef.nativeElement.value;
    if (inputValue === '.') {
      this.elemRef.nativeElement.value = '0.';
    }
  }
}

关键修改说明:

  1. 光标位置精准判断:新增isCursorBeforeDot变量,明确区分光标在小数点前后的场景,确保在小数点前输入数字不受小数位数限制。
  2. minValue逻辑修复:专门处理输入框为空或仅含小数点的情况,通过计算临时值(输入数字+当前值)判断是否符合最小值要求,避免NaN导致的错误阻止。
  3. maxValue逻辑完善:根据光标位置动态计算输入后的临时值,不管光标在小数点前还是后,都能准确校验是否超过最大值。
  4. 小数位数限制优化:仅当光标在小数点后方时,才触发小数位数限制,彻底解决了无法在小数点前输入数字的问题。
  5. 可选体验优化:新增blur事件处理,当输入框只剩小数点时,自动补全为0.,避免用户输入不合法的格式。

使用注意:

  • 若设置minValue="0",允许输入0.xx格式;若设置minValue="1",则会阻止0.xx这类小于1的输入。
  • 保留了原有的快捷键支持(Ctrl+A/C/X、删除键、方向键等),不影响用户常规操作习惯。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:30:48