赞
踩
在平时开发的过程中,产品终会提一些另辟蹊径的建议,例如我们在做输入限制的时候,产品希望可以根据输入字符汉字不同去做不同限制;例如:限制输入10个字符或者5个汉字
// 嫌弃代码不全的队友请放心,下面会有完整的代码 // @HostListener('compositionstart') onCompositionstart() { this.isComposite = true; } // @HostListener('compositionEnd', ['$event']) onCompositionEnd($event) { this.isComposite = false; this.onInput($event); } // @HostListener('input', ['$event']) onInput($event) { if (!$event || this.isComposite) { return; } const target = $event.target; if (this.CN) { target.value = this.limitLength(target.value, this.maxLen); this.val = this.limitLength(target.value, this.maxLen); } else { let newValue = $event.target.value; if (newValue && this.maxLen > -1 && newValue.length > this.maxLen) { newValue = newValue.substring(0, this.maxLen); $event.target.value = newValue; } } }
// angular 代码;就是paste事件,其他框架通用这个方法 @HostListener('paste', ['$event']) onPaste(event: ClipboardEvent) { // 一个检测事件,监测限制值是否为负数 if (!this.isTriggerKeyEvents()) { return; } // 禁止输入 event.preventDefault(); let currentVal = this.val; if (this.maxLen > -1 || this.numberOnly) { // 获取粘贴的值 let clipboardData = event.clipboardData.getData('text/plain'); if (this.numberOnly) { let pastedInput: string = clipboardData.replace(/\D/g, ''); // get a number-only string this.val = currentVal + pastedInput; } if (this.maxLen > -1) { if (this.CN) { // 限制的汉字 this.val = this.limitPaste(currentVal, this.maxLen, clipboardData); this.calculateCurrentLen(); } else { let pastedInput: string = clipboardData.substring(0, this.maxLen); this.val = currentVal + pastedInput; } } } } private limitPaste(value: string, byteLength: number, pastedVal: string) { if (!pastedVal) { return } if (!value) { let pastedValue = pastedVal.replace(/[^\x00-\xff]/g, "**"); let limitDate = pastedValue.substr(0, byteLength); return this.limtFunc(limitDate, byteLength, pastedVal) } let newvalue = value.replace(/[^\x00-\xff]/g, "**"); let length = newvalue.length;//获取内容长度 let split_value = value + pastedVal; if (length * 1 >= byteLength * 1) { let limitDate = newvalue.substr(0, byteLength); return this.limtFunc(limitDate, byteLength, value) } if (length * 1 < byteLength * 1) { let pastedValue = pastedVal.replace(/[^\x00-\xff]/g, "**"); let val = newvalue + pastedValue; let limitDate = val.substr(0, byteLength); return this.limtFunc(limitDate, byteLength, split_value) } }
// typeScript,js时不需要参数后面的类型 limitLength(value: string, byteLength: number) { let newvalue = value.replace(/[^\x00-\xff]/g, "**"); //输入内容 let length = newvalue.length;//获取内容长度 //当填写的字节数小于设置的字节数 if (length * 1 <= byteLength * 1) { return value; } let limitDate = newvalue.substr(0, byteLength); let count = 0; let limitvalue = ""; for (let i = 0; i < limitDate.length; i++) { let flat = limitDate.substr(i, 1); if (flat == "*") { count++; } } let size = 0; //if 基点是×; 判断在基点内有×为偶数还是奇数 if (count % 2 == 0) { //当为偶数时 size = count / 2 + (byteLength * 1 - count); limitvalue = value.substr(0, size); } else { //当为奇数时 size = (count - 1) / 2 + (byteLength * 1 - count); limitvalue = value.substr(0, size); } return limitvalue; }
由于我的是angular的代码,因此使用了ts而非js,但是看起来各位大佬一定觉得很 easy,毕竟我这个只是总结前人经验应用到我这里而已
我这边将input封装为组件,支持限制字符、汉字、粘贴、仅输入数字功能
html:
<div class="cil-input-wrapper flex-wrap row-flex"> <div class="flex-wrap col-flex" *ngIf="label"> <label for="cil-input" class="cil-input-lbl"> <span class="form-required" *ngIf="isRequired">*</span> {{ label }} </label> </div> <div class="flex-wrap col-flex input-container"> <input id="cil-input" class="cil-input" type="text" [(ngModel)]="val" [placeholder]="placeholder" (input)="onInput($event)" (compositionstart)="onCompositionstart()" (compositionend)="onCompositionEnd($event)" (change)="onChange($event)" (keyup)="onChange($event)" (blur)="onBlur($event)" [attr.disabled]="isDisabled ? '' : null" [class.disabled]="isDisabled" [style.padding-right.px]="(maxLen > -1 && maxLen < 1000) ? '65' : '10'" autocomplete="off"> <span class="error-message" *ngIf="errorMessage">{{ errorMessage }}</span> <div class="cil-len" *ngIf="maxLen > -1 && maxLen < 1000"> <span class="cur-length">{{ currentLen }}</span> / <span>{{ maxLen }}</span> </div> </div> </div>
import { Component, ViewEncapsulation, ChangeDetectionStrategy, Input, OnInit, forwardRef, ChangeDetectorRef, OnChanges, SimpleChanges, HostListener } from "@angular/core"; import { NG_VALUE_ACCESSOR, NG_VALIDATORS, ControlValueAccessor, Validator, ValidationErrors, AbstractControl } from "@angular/forms"; @Component({ selector: `cil-input`, templateUrl: 'input.html', styleUrls: ['input.scss'], encapsulation: ViewEncapsulation.None, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CilInput), multi: true, }, { provide: NG_VALIDATORS, useExisting: forwardRef(() => CilInput), multi: true, }] }) export class CilInput implements OnInit, OnChanges, ControlValueAccessor, Validator { val: string; private navigationKeys = [ 'Backspace', 'Delete', 'Tab', 'Escape', 'Enter', 'Home', 'End', 'ArrowLeft', 'ArrowRight', 'Clear', 'Copy', 'Paste' ]; currentLen: number = 0; chineseReg = /[^\x00-\xff]/g; // 输入完成的标记 isComposite: boolean = false; @Input() label: string; @Input() isRequired: boolean; @Input() placeholder: string = ''; @Input() errorMessage: string; @Input() isDisabled: boolean; @Input() CN: boolean = false; // Default -1 indicate that the length of input is not limited // The max of maxLen is 999 @Input() maxLen: number = -1; @Input() numberOnly: boolean = false; private emitChange = (_: any) => { }; constructor() { } ngOnInit() { } ngOnChanges(changes: SimpleChanges): void { if (changes) { } } onChange(event: any) { this.onBlur(event); } onBlur(event: any) { // this.onInput(event); this.emitChange(this.val); } writeValue(obj: any): void { if (obj || obj === '') { this.val = obj; if (this.maxLen > -1) { this.calculateCurrentLen(); } } } registerOnChange(fn: any): void { this.emitChange = fn; } registerOnTouched(fn: any): void { } validate(control: AbstractControl): ValidationErrors { // TODO: customize validation return null; } @HostListener('keyup', ['$event']) onKeyup(e: KeyboardEvent) { // console.log('>>>>>>') if (this.maxLen === -1) { return; } if (this.maxLen > -1) { this.calculateCurrentLen(); // Hack: when typing chinese character, input control will not prevent the character typing // let chineseCharLen = this.val ? (this.val.match(this.chineseReg) || []) : []; // if (chineseCharLen.length > 0) { // let len = this.maxLen - chineseCharLen.length + 1; // this.val = this.val.substring(0, len); // } } if (this.numberOnly) { this.val = this.val ? this.val.replace(this.chineseReg, '') : ''; } } @HostListener('keydown', ['$event']) onKeyDown(e: KeyboardEvent) { if (!this.isTriggerKeyEvents()) { return; } if ( this.navigationKeys.indexOf(e.key) > -1 || // Allow: navigation keys: backspace, delete, arrows etc. (e.key === 'a' && e.ctrlKey === true) || // Allow: Ctrl+A (e.key === 'c' && e.ctrlKey === true) || // Allow: Ctrl+C (e.key === 'v' && e.ctrlKey === true) || // Allow: Ctrl+V (e.key === 'x' && e.ctrlKey === true) || // Allow: Ctrl+X (e.key === 'a' && e.metaKey === true) || // Allow: Cmd+A (Mac) (e.key === 'c' && e.metaKey === true) || // Allow: Cmd+C (Mac) (e.key === 'v' && e.metaKey === true) || // Allow: Cmd+V (Mac) (e.key === 'x' && e.metaKey === true) // Allow: Cmd+X (Mac) ) { return; } if (this.maxLen > -1) { let hightlightText = window.getSelection() + ''; let currentLen = 0; if (this.CN) { let chineseCharLen = this.val ? (this.val.match(this.chineseReg) || []) : []; currentLen = this.val ? this.val.length + chineseCharLen.length : 0; } else { currentLen = this.val ? this.val.length : 0; } if (this.val && currentLen >= this.maxLen && hightlightText === '') { e.preventDefault(); } } if (this.numberOnly) { if (isNaN(Number(e.key))) { e.preventDefault(); } } } // @HostListener('compositionstart') onCompositionstart() { this.isComposite = true; } // @HostListener('compositionEnd', ['$event']) onCompositionEnd($event) { this.isComposite = false; this.onInput($event); } // @HostListener('input', ['$event']) onInput($event) { if (!$event || this.isComposite) { return; } const target = $event.target; if (this.CN) { target.value = this.limitLength(target.value, this.maxLen); this.val = this.limitLength(target.value, this.maxLen); } else { let newValue = $event.target.value; if (newValue && this.maxLen > -1 && newValue.length > this.maxLen) { newValue = newValue.substring(0, this.maxLen); $event.target.value = newValue; } } } limitLength(value: string, byteLength: number) { let newvalue = value.replace(/[^\x00-\xff]/g, "**"); //输入内容 let length = newvalue.length;//获取内容长度 //当填写的字节数小于设置的字节数 if (length * 1 <= byteLength * 1) { return value; } let limitDate = newvalue.substr(0, byteLength); let count = 0; let limitvalue = ""; for (let i = 0; i < limitDate.length; i++) { let flat = limitDate.substr(i, 1); if (flat == "*") { count++; } } let size = 0; //if 基点是×; 判断在基点内有×为偶数还是奇数 if (count % 2 == 0) { //当为偶数时 size = count / 2 + (byteLength * 1 - count); limitvalue = value.substr(0, size); } else { //当为奇数时 size = (count - 1) / 2 + (byteLength * 1 - count); limitvalue = value.substr(0, size); } return limitvalue; } @HostListener('paste', ['$event']) onPaste(event: ClipboardEvent) { if (!this.isTriggerKeyEvents()) { return; } event.preventDefault(); let currentVal = this.val; if (this.maxLen > -1 || this.numberOnly) { let clipboardData = event.clipboardData.getData('text/plain'); if (this.numberOnly) { let pastedInput: string = clipboardData.replace(/\D/g, ''); // get a number-only string this.val = currentVal + pastedInput; } if (this.maxLen > -1) { if (this.CN) { this.val = this.limitPaste(currentVal, this.maxLen, clipboardData); this.calculateCurrentLen(); } else { let pastedInput: string = clipboardData.substring(0, this.maxLen); this.val = currentVal + pastedInput; } } } } private limitPaste(value: string, byteLength: number, pastedVal: string) { if (!pastedVal) { return } if (!value) { let pastedValue = pastedVal.replace(/[^\x00-\xff]/g, "**"); let limitDate = pastedValue.substr(0, byteLength); return this.limtFunc(limitDate, byteLength, pastedVal) } let newvalue = value.replace(/[^\x00-\xff]/g, "**"); let length = newvalue.length;//获取内容长度 let split_value = value + pastedVal; if (length * 1 >= byteLength * 1) { let limitDate = newvalue.substr(0, byteLength); return this.limtFunc(limitDate, byteLength, value) } if (length * 1 < byteLength * 1) { let pastedValue = pastedVal.replace(/[^\x00-\xff]/g, "**"); let val = newvalue + pastedValue; let limitDate = val.substr(0, byteLength); return this.limtFunc(limitDate, byteLength, split_value) } } private limtFunc(limitVal: string, byteLength: number, split_value: string) { let count = 0; let limitvalue = ""; for (let i = 0; i < limitVal.length; i++) { let flat = limitVal.substr(i, 1); if (flat == "*") { count++; } } let size = 0; //if 基点是×; 判断在基点内有×为偶数还是奇数 if (count % 2 == 0) { //当为偶数时 size = count / 2 + (byteLength * 1 - count); limitvalue = split_value.substr(0, size); } else { //当为奇数时 size = (count - 1) / 2 + (byteLength * 1 - count); limitvalue = split_value.substr(0, size); } return limitvalue } private calculateCurrentLen() { if (this.CN) { let chineseCharLen = this.val ? (this.val.match(this.chineseReg) || []) : []; this.currentLen = this.val ? this.val.length + chineseCharLen.length : 0; } else { this.currentLen = this.val ? this.val.length : 0; } this.currentLen = this.currentLen > this.maxLen ? this.maxLen : this.currentLen; } private isTriggerKeyEvents() { return this.maxLen !== -1 || this.numberOnly; } }
此时在项目中应用就很简单
<cil-input formControlName="testName" [isRequired]="true" [errorMessage]="requiredMessage"
[placeholder]="'请输入您的品牌名称'" [maxLen]="10" [CN]="true"></cil-input>
<span style="padding: 10px 0 10px 100px;">输入内容: {{f.testName.value}}</span>
<br>
<cil-input [label]="'汉语字符'" [(ngModel)]="inputValCN" [isRequired]="true" [placeholder]="'请输入您的商户名称'" [maxLen]="10" [CN]="true"></cil-input>
当有属性maxLen时候进行限制,默认对中文不做任何校验,当传递CN为true的时候则对中文进行限制;
学海无涯,回头是岸
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。