Angular中input type=number禁止小数与指数的验证问题
解决方案
因为Angular会自动把<input type="number">的输入转换为数字类型,导致你没法通过control.value拿到用户输入的原始字符串(比如10.0会被转成10,2e1会被转成20),所以核心思路是直接获取用户输入的原始文本,用正则做格式校验,同时拦截非法输入。
方法1:自定义验证指令(推荐)
写一个自定义指令,既能做表单验证,还能实时拦截不符合规则的输入:
import { Directive, HostListener } from '@angular/core'; import { NG_VALIDATORS, Validator, FormControl } from '@angular/forms'; @Directive({ selector: '[appIntegerPercentValidator]', providers: [{ provide: NG_VALIDATORS, useExisting: IntegerPercentValidatorDirective, multi: true }] }) export class IntegerPercentValidatorDirective implements Validator { validate(control: FormControl): { [key: string]: any } | null { // 直接取输入框的原始值,不用control.value const inputElement = control.nativeElement as HTMLInputElement; const rawValue = inputElement?.value || ''; // 正则规则:只允许0、1-99、100,不能有小数点、指数符号 const validRegex = /^([1-9]\d?|100|0)$/; if (!validRegex.test(rawValue)) { return { invalidPercent: true }; } // 额外校验数值范围,防止用户通过粘贴等方式输入超范围内容 const numValue = Number(rawValue); if (numValue < 0 || numValue > 100) { return { outOfRange: true }; } return null; } // 实时拦截非法输入 @HostListener('input', ['$event']) onInput(event: InputEvent) { const inputElement = event.target as HTMLInputElement; const rawValue = inputElement.value; // 允许空值,方便用户输入过程中的临时状态 const validRegex = /^([1-9]\d?|100|0)?$/; if (!validRegex.test(rawValue)) { // 恢复到上一次的合法值 inputElement.value = inputElement.dataset['lastValidValue'] || ''; } else { // 保存当前合法值 inputElement.dataset['lastValidValue'] = rawValue; } } // 初始化时保存初始值 @HostListener('ngModelChange', ['$event']) onModelChange(value: any) { const inputElement = document.querySelector(`[formControlName="${(this as any).name}"]`) as HTMLInputElement; if (inputElement) { inputElement.dataset['lastValidValue'] = inputElement.value; } } }
模板中使用:
<input type="number" appIntegerPercentValidator formControlName="percent"> <!-- 错误提示 --> <div *ngIf="form.get('percent')?.hasError('invalidPercent')"> 请输入0-100之间的整数,禁止小数和指数形式 </div> <div *ngIf="form.get('percent')?.hasError('outOfRange')"> 输入值必须在0-100之间 </div>
方法2:组件内直接处理(简单场景适用)
如果不想写指令,也可以在组件里直接监听输入事件:
import { Component, ViewChild, ElementRef } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; @Component({ template: ` <input #percentInput type="number" [formControl]="percentControl" (input)="validateInput()"> <div *ngIf="percentControl.hasError('invalidPercent')"> 请输入0-100之间的整数,禁止小数和指数形式 </div> ` }) export class PercentComponent { @ViewChild('percentInput') percentInput!: ElementRef<HTMLInputElement>; percentControl = new FormControl('', [Validators.required]); validateInput() { const rawValue = this.percentInput.nativeElement.value; const validRegex = /^([1-9]\d?|100|0)$/; if (!validRegex.test(rawValue)) { this.percentControl.setErrors({ invalidPercent: true }); // 可选:恢复到上一次合法值 this.percentInput.nativeElement.value = this.percentInput.nativeElement.dataset['lastValid'] || ''; } else { this.percentControl.setErrors(null); this.percentInput.nativeElement.dataset['lastValid'] = rawValue; } } }
关键注意事项
- 必须直接获取输入框的原始字符串,不能用
FormControl.value——Angular的自动数字转换会抹掉你需要校验的格式信息(比如.0、e符号)。 - 正则
^([1-9]\d?|100|0)$的作用:- 匹配单独的
0 - 匹配1-99的整数(无前置零)
- 精确匹配
100
- 匹配单独的
- 实时拦截输入能提升用户体验,避免用户输入非法内容后才收到错误提示。
内容的提问来源于stack exchange,提问作者arunkumaraqm
相关产品推荐
相关产品推荐

