Angular表单控件中带验证的信用卡刷卡输入处理问题
问题:Angular信用卡刷卡器完整数据获取方案
我有一个支持信用卡支付的Angular应用,搭配了信用卡刷卡器。目前能读取信用卡数据,但刷卡时仅在信用卡输入框填充前16位数字(不一定是完整卡号),其余数据被丢弃。使用keyup或change事件只能获取输入框内的数字,拿不到完整刷卡数据。想知道能不能在表单保存和验证前处理完整的刷卡数据?
现有代码
表单定义
this.paymentForm = this._fb.group({ email: ['', [Validators.required, Validators.pattern('(?:[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])')]], expirationMonth: ['01', [CreditCardValidators.validateExpDate]], expirationYear: ['2024', [CreditCardValidators.validateExpDate]], cvv: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(4)]], creditCard: ['', [CreditCardValidators.validateCCNumber]], });
信用卡输入框HTML
<div> <label for="cc-number">Card Number</label> <input matInput id="cc-number" (input)="processCard($event)" formControlName="creditCard" class="input-cart-number" type="num" autocomplete="cc-number" ccNumber name='cardNumber' autofocus placeholder="XXXX XXXX XXXX XXXX" length="16" style="width: 280px; font-size: 15px;"/> <br> <mat-error *ngIf="f.creditCard.errors && f.creditCard.touched">Card number is <strong>required</strong> </mat-error> </div>
现有事件处理
processCard(event){ console.log('cc ' +JSON.stringify(event)); }
刷卡返回完整数据示例
%B6011361000006668^DISCOVER TESTCARD/DEVKIT^251210123456789?;**6011361000006668=2512**10123456789?
其中卡号为6011361000006668,有效期为12/25。
解决方案
1. 核心问题分析
当前表单控件的CreditCardValidators.validateCCNumber验证器会实时过滤输入内容,导致刷卡器输出的完整数据被截断。要获取完整数据,必须绕过这个实时验证的干扰。
2. 推荐实现方案:隐藏输入框接收完整数据
新增一个不绑定表单控件、无验证规则的隐藏输入框,让刷卡器的完整输出直接进入这个框,再从这里解析数据并填充表单。
修改HTML代码
<div> <label for="cc-number">Card Number</label> <!-- 原有输入框保留,用于手动输入或展示格式化卡号 --> <input matInput id="cc-number" formControlName="creditCard" class="input-cart-number" type="num" autocomplete="cc-number" ccNumber name='cardNumber' autofocus placeholder="XXXX XXXX XXXX XXXX" length="16" style="width: 280px; font-size: 15px;"/> <!-- 新增隐藏输入框,专门接收完整刷卡数据 --> <input #swipeInput type="text" style="position: absolute; left: -9999px;" (input)="handleSwipe($event)"/> <br> <mat-error *ngIf="f.creditCard.errors && f.creditCard.touched">Card number is <strong>required</strong> </mat-error> </div>
组件中解析并填充数据
import { ViewChild, ElementRef } from '@angular/core'; // 获取隐藏输入框的DOM引用 @ViewChild('swipeInput') swipeInput!: ElementRef<HTMLInputElement>; handleSwipe(event: Event) { const fullSwipeData = (event.target as HTMLInputElement).value; if (!fullSwipeData) return; // 解析刷卡数据(匹配示例格式) const cardNumberMatch = fullSwipeData.match(/%B(\d+)\^/); const expiryMatch = fullSwipeData.match(/\^(\d{4})/); if (cardNumberMatch && expiryMatch) { const cardNumber = cardNumberMatch[1]; // 解析有效期:示例中2512对应2025年12月 const expiryYear = `20${expiryMatch[1].slice(0, 2)}`; const expiryMonth = expiryMatch[1].slice(2); // 自动填充表单字段 this.paymentForm.patchValue({ creditCard: cardNumber, expirationYear: expiryYear, expirationMonth: expiryMonth }); // 清空隐藏输入框,准备下一次刷卡 this.swipeInput.nativeElement.value = ''; } }
3. 优化焦点处理(可选)
确保刷卡器输出直接进入隐藏输入框,可在组件初始化时设置焦点:
ngAfterViewInit() { this.swipeInput.nativeElement.focus(); }
如果需要保留手动输入功能,可在原有输入框的焦点事件中切换:
<input matInput id="cc-number" (focus)="swipeInput.nativeElement.blur()" (blur)="swipeInput.nativeElement.focus()" formControlName="creditCard" ... />
内容的提问来源于stack exchange,提问作者coder123
相关产品推荐
相关产品推荐

