如何修复Angular 8指令正则表达式以支持负小数?
问题分析与解决方案
你的问题出在实时输入的中间状态校验上:在线测试正则时你输入的是完整的负小数(比如-12.34),但指令是在每一次按键时校验输入后的即时值——当你第一次输入负号-时,next的值是"-",而你修改后的正则/^-?[0-9]\d*(\.\d+)?$/g并不匹配这个单独的负号,所以被event.preventDefault()阻止了输入。
另外,原指令是限制最多两位小数的,你的新正则没有保留这个限制,同时全局标志g在这里也不需要,会干扰匹配逻辑。
修改后的完整指令代码
import {Directive, ElementRef, HostListener} from '@angular/core'; @Directive({ selector: '[signedNumeric]' }) export class SignedNumericDirective { // 允许三种状态:空、单独负号、正负两位小数 private regex = { decimal: new RegExp(/^$|^-$|^-?\d+(?:\.\d{0,2})?$/) }; private specialKeys = { decimal: [ 'Backspace', 'Delete', 'Tab', 'End', 'Home', 'ArrowLeft', 'ArrowRight' ] }; constructor(private el: ElementRef) { } @HostListener('keydown', [ '$event' ]) onKeyDown(event: KeyboardEvent) { // 特殊按键直接放行 if (this.specialKeys['decimal'].indexOf(event.key) !== -1) { return; } const current: string = this.el.nativeElement.value; // 已有负号时,禁止再次输入负号 if (current.includes('-') && event.key === '-') { event.preventDefault(); return; } const next: string = current.concat(event.key); // 校验输入后的值是否合法 if (next && !next.match(this.regex['decimal'])) { event.preventDefault(); } } }
关键修改点说明
正则表达式调整:
^$:允许输入框为空^-$:允许单独输入负号(作为输入负小数的中间状态)^-?\d+(?:\.\d{0,2})?$:允许正负整数、最多两位小数的正负小数,保留原指令的小数位数限制
增加负号重复输入拦截:
- 判断当前输入框已有负号时,阻止再次输入负号,避免出现
--123这类非法值
- 判断当前输入框已有负号时,阻止再次输入负号,避免出现
移除全局标志
g:- 单值匹配不需要全局标志,
g会导致match方法返回数组而非布尔值(在某些场景下会干扰校验逻辑)
- 单值匹配不需要全局标志,
测试验证
现在可以正常输入以下内容:
- 负号开头的小数:
-12.34、-0.5、-100 - 正小数:
34.45、0.7、1200 - 输入过程中的中间状态:先输
-,再输数字,再输小数点和小数位
同时会拦截以下非法输入:
- 多个负号:
--12 - 超过两位小数:
-12.345 - 非数字/负号/小数点的字符:
abc、-12a
内容的提问来源于stack exchange,提问作者user2304483
相关产品推荐
相关产品推荐

