Angular 16百分比输入框格式化后光标错位问题求助
Angular 百分比输入框光标错位问题解决方案
在Angular 16项目中使用TypeScript和Tailwind构建百分比输入框,要求存储0-100的数值并显示两位小数。当前实现通过原生oninput事件格式化值,但存在光标错位问题:
- 在默认值
0前输入1,值会格式化为10.00,但光标跳至末尾 - 输入
50时,按下5后值变为5.00,光标跳至末尾,后续输入0会变成5.000被限制,无法完成输入
核心思路
放弃原生oninput直接修改输入框值的方式,改用Angular组件逻辑处理值的格式化,同时记录并恢复光标位置,避免光标错位。具体步骤:
- 将输入框类型从
number改为text,便于灵活处理字符串格式 - 在用户输入时记录光标位置
- 格式化值后,根据字符串长度变化调整光标位置并恢复
实现代码
模板部分
<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
相关产品推荐
相关产品推荐

