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

Angular 16百分比输入框格式化后光标错位问题求助

Angular 百分比输入框光标错位问题解决方案

在Angular 16项目中使用TypeScript和Tailwind构建百分比输入框,要求存储0-100的数值并显示两位小数。当前实现通过原生oninput事件格式化值,但存在光标错位问题:

  • 在默认值0前输入1,值会格式化为10.00,但光标跳至末尾
  • 输入50时,按下5后值变为5.00,光标跳至末尾,后续输入0会变成5.000被限制,无法完成输入

核心思路

放弃原生oninput直接修改输入框值的方式,改用Angular组件逻辑处理值的格式化,同时记录并恢复光标位置,避免光标错位。具体步骤:

  1. 将输入框类型从number改为text,便于灵活处理字符串格式
  2. 在用户输入时记录光标位置
  3. 格式化值后,根据字符串长度变化调整光标位置并恢复

实现代码

模板部分

<div class="flex">
  <span class="text-primary text-left px-2 border-b border-[#E0E0E0] w-3/4">
    <input
      #percentInput
      class="text-3xl w-full"
      type="text"
      matInput
      placeholder="0.00 %"
      required
      [(ngModel)]="pointsEstimatedUtilization"
      (input)="saveCursorPosition(percentInput)"
      (ngModelChange)="handleInputChange(percentInput)"
    />
  </span>
  <span class="w-1/4 flex justify-center items-center text-xl">%</span>
</div>

组件逻辑(TypeScript)

import { Component, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-your-component', // 替换为你的组件选择器
  templateUrl: './your-component.component.html',
  styleUrls: ['./your-component.component.css']
})
export class YourComponent {
  pointsEstimatedUtilization: string = '0.00';
  private cursorPosition: number = 0;

  @ViewChild('percentInput') percentInput!: ElementRef<HTMLInputElement>;

  saveCursorPosition(input: HTMLInputElement) {
    this.cursorPosition = input.selectionStart || 0;
  }

  handleInputChange(input: HTMLInputElement) {
    // 过滤非数字和小数点的非法字符
    let rawValue = this.pointsEstimatedUtilization.replace(/[^0-9.]/g, '');
    
    // 限制仅保留一个小数点
    const valueParts = rawValue.split('.');
    if (valueParts.length > 2) {
      rawValue = `${valueParts[0]}.${valueParts.slice(1).join('')}`;
    }

    // 截断小数部分至两位
    if (valueParts.length === 2) {
      rawValue = `${valueParts[0]}.${valueParts[1].slice(0, 2)}`;
    }

    // 转换为数值并限制范围在0-100之间
    const numValue = parseFloat(rawValue) || 0;
    const clampedValue = Math.max(0, Math.min(numValue, 100));

    // 格式化为两位小数
    const formattedValue = clampedValue.toFixed(2);

    // 计算光标位置偏移量:根据原字符串和新字符串的长度差调整
    const lengthDiff = formattedValue.length - this.pointsEstimatedUtilization.length;
    let newCursorPos = this.cursorPosition + lengthDiff;

    // 确保光标位置不越界
    newCursorPos = Math.max(0, Math.min(newCursorPos, formattedValue.length));

    // 更新绑定值
    this.pointsEstimatedUtilization = formattedValue;

    // 异步恢复光标位置(等待Angular更新DOM)
    setTimeout(() => {
      input.setSelectionRange(newCursorPos, newCursorPos);
    }, 0);
  }
}

关键说明

  • 输入类型改为text:避免原生number输入框的默认行为限制,更灵活处理格式化逻辑
  • 光标位置记录与恢复:在input事件中实时记录光标位置,格式化后根据字符串长度变化调整位置,确保光标停留在用户输入的预期位置
  • 值的合法性处理:过滤非法字符、限制小数点数量、截断小数位、数值范围限制,确保输入值符合要求
  • 异步恢复光标:利用setTimeout等待Angular完成DOM更新后再设置光标,保证生效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 16:35:01