免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Angular封裝表單控件以及一些思想
前端框架的強大無疑給開發(fā)者省去了不少煩惱,又因比較完善的UI庫支撐,讓部分后端開發(fā)者能夠省去大量樣式設計的時間成本,縱然如此,業(yè)務的多變性是框架本身無法預料的,很多的控件功能在實際開發(fā)中總是不夠完善和靈活,所以需要開發(fā)者結(jié)合業(yè)務需求進行再次封裝這些UI控件/組件。

表單控件

常規(guī)組件只需要根據(jù)官方指引,寫好數(shù)據(jù)傳輸?shù)姆绞胶陀嗛喖纯扇我馐褂?,表單控件有點特殊,按照常規(guī)方式寫出來的組件使用在表單中,綁定ngModel或者formControlName,隨之而來的是一個報錯:
RROR Error: No value accessor for form control with name: 'userName'


ControlValueAccessor
Defines an interface that acts as a bridge between the Angular forms API and a native element in the DOM

只有實現(xiàn)了這個接口才可以完成像普通表單元素那樣使用和驗證。

interface ControlValueAccessor {  writeValue(obj: any): void  registerOnChange(fn: any): void  registerOnTouched(fn: any): void  setDisabledState(isDisabled: boolean)?: void}

你的控件必須包含上述方法;此外,控件內(nèi)部要有value的get實現(xiàn),以及最好有個與value等值的別名變量(想不明白別急,看代碼);一個簡單的input控件封裝應該類似這樣:

export class MyInputComponent implements OnInit, ControlValueAccessor {  value: string | number;  @Input() disabled: boolean;  @Input() placeholder: string;  @Input() type = 'text';  constructor() { }  ngOnInit() {  }  writeValue(data: any) {    this.value = data;  }  registerOnChange(fn: any) {  }  registerOnTouched(fn: any) {  }  setDisabledState(disabled: boolean) {    this.disabled = disabled;  }}

其實封裝工作只完成一半,組件裝飾器元數(shù)據(jù)完整:

@Component({  // tslint:disable-next-line: component-selector  selector: 'my-input',  templateUrl: './my-input.component.html',  styleUrls: ['./my-input.component.scss'],  providers: [{    provide: NG_VALUE_ACCESSOR,    useExisting: forwardRef(() => MyInputComponent),    multi: true  }]})

至此,控件在form表單中使用不會報錯;表單內(nèi)放置一個查詢按鈕,用來輸出表單狀態(tài):

<form nz-form [formGroup]="form" (ngSubmit)="submit(form)">  <div nz-row nzFlex [nzGutter]="8">    <div nz-col [nzSpan]="6">      <nz-form-item>        <nz-form-label [nzSpan]="10">userName</nz-form-label>        <nz-form-control [nzSpan]="14">          <my-input formControlName="userName"></my-input>        </nz-form-control>      </nz-form-item>    </div>  </div>  <button nz-button type="submit" [nzType]="'primary'">查詢</button></form>
ngOnInit() {    this.form = this.fb.group({      userName: [2]    });  }  submit(form: FormGroup) {    console.log(form);  }

封裝控件內(nèi)部:

<div class="my-input">  <input type="{{type}}" value="{{value}}"  placeholder="{{placeholder}}"></div>

通過formControlName的綁定方式將userName傳入控件,控件通過writeValue方法接收并賦值到自身屬性value,用于與原生input交互,此時我們手動輸入內(nèi)容為數(shù)字3,然后打印:


可以看到表單沒有獲取到最新的值,這是因為目前位置表單獲取組件的value還是初始值,我們也沒有提供改變value的方法機制,修改html:

<div class="my-input">  <input type="{{type}}" [ngModel]="actualValue" placeholder="{{placeholder}}" (ngModelChange)="modelChange($event)"></div>

這里稍微解釋input綁定數(shù)據(jù)與觸發(fā)的更新方法可以選擇原生的value和input進行更新,也可以選擇ng提供的ngModel和ngModelChange事件更新控件,區(qū)別在于使用原生input的輸入事件,要使用到事件對象展開找到元素的value屬性值;而使用ng官方框架自帶的事件,事件對象$event就是最新的value值。
新增set value方法:

set value(data) {    this.actualValue = data;    // 通知表單value更新    this.onChange(data);}registerOnChange(fn: any) {    // 注冊表單的value改變通知方法    this.onChange = fn;}modelChange(event) {    this.value = event;}

輸入 3 ,查詢打?。?br>

實現(xiàn)原生input基礎(chǔ)屬性

這個幾乎是一條默認的規(guī)則,封裝的控件至少實現(xiàn)原生input的基礎(chǔ)屬性功能,在此基礎(chǔ)上再進行滿足業(yè)務需求。

  1. type
  2. maxlength
  3. minlength
  4. placeholder
  5. ......

這里只討論type為text和number的情況,radio等其它類型沒必要深入。
我們不能直接使用maxlength進行與input綁定,至少寫法不是很好,比較妥善的做法是動態(tài)的判斷長度值,并且將正確的值設置到原生input屬性中。
為此修改html:

<div class="my-input">  <input    type="{{type}}"    #inputElement    [(ngModel)]="actualValue"    placeholder="{{placeholder}}"    (ngModelChange)="modelChange($event)"  ></div>

注入 Renderer2,用于對原生元素操作

ngOnChanges(changes: SimpleChanges) {    this.initAttributes(changes);  }initAttributes(changes: SimpleChanges) {    for (const key in changes) {      if (changes.hasOwnProperty(key)) {        const element = changes[key];        if (element) {          this.render2.setProperty(this.inputElement.nativeElement, key, element.currentValue);        }      }    }  }
Validator
ngOnInit() {    this.form = this.fb.group({      userName: [2, [Validators.required, Validators.minLength(3)]]    });  }

經(jīng)過打印測試,表單的狀態(tài)正確 √

適當使用指令

假如此時需要對輸入內(nèi)容攔截處理,目前在不寫input事件的情況下無法做到,假如針對一個type=number類型的輸入框,設置最大值,超過這個值不會改變,原生input元素確實有max屬性支撐驗證,但是它無法改變value值,也就是說假如這個最大值不是必要驗證屬性,那么表單還是可以提交最新的超出值,用指令可以攔截處理。

import { Directive, ElementRef, HostListener, Renderer2, Input } from '@angular/core';@Directive({  selector: '[appInput]',})export class InputDirective {  constructor(    private el: ElementRef,    private render: Renderer2  ) {    // 添加預設class    render.addClass(this.el.nativeElement, 'my-input');  }  @HostListener('input') onInputChange() {    const element = this.el.nativeElement;    if (element.max && Number(element.value) >= Number(element.max)) {      this.render.setProperty(element, 'value', element.max);    }  }}
<div class="my-input">  <input    appInput    #inputElement    [(ngModel)]="actualValue"    placeholder="{{placeholder}}"    (ngModelChange)="modelChange($event)"  ></div>
<my-input formControlName="userName" [maxLength]="5" [type]="'number'" [max]="250"></my-input>

表單驗證測試:


form表單拿到的值還是輸入的非法值,這是因為模型值與原生元素之間沒有真正的做到統(tǒng)一一致,
指令中核心代碼修改:

@Output() valueChange = new EventEmitter();@HostListener('input') onInputChange() {    const element = this.el.nativeElement;    if (element.max && Number(element.value) >= Number(element.max)) {      this.render.setProperty(element, 'value', element.max);      this.valueChange.emit(element.value);    }}

在input 標簽上添加事件監(jiān)聽(valueChange)="onValueChange($event)"

  onValueChange(event) {    this.modelChange(event);  }

表單獲取的值與原生控件的value一致,一般自行封裝原生控件還需要加入自己的樣式,甚至有時候我們封裝的主要目的就是美化樣式,動態(tài)添加class示例:

@Directive({  selector: '[appInput]',  // tslint:disable-next-line: no-host-metadata-property  host: {    '[class.my-input-disabled]': 'disabled'  }})export class InputDirective {  constructor(    private el: ElementRef,    private render: Renderer2  ) {    // 添加預設class    render.addClass(this.el.nativeElement, 'my-input');  }  @Input() @InputBoolean() disabled = false;  @Output() valueChange = new EventEmitter();  @HostListener('input') onInputChange() {    const element = this.el.nativeElement;    if (element.max && Number(element.value) >= Number(element.max)) {      this.render.setProperty(element, 'value', element.max);      this.valueChange.emit(element.value);    }    console.log(element.value);  }}
結(jié)尾:總結(jié)下封裝表單控件的原則:
1.原生控件支持的屬性機制理論上需要全部保留實現(xiàn)(特別針對某業(yè)務封裝除外);
2.不涉及復雜的數(shù)據(jù)處理、判斷等邏輯的優(yōu)先使用指令處理,例如本例中input的大多數(shù)功能都可以不做封裝,原生標簽input已經(jīng)很完善;
3.get和set方法必須體現(xiàn),且要保持模型數(shù)據(jù)與原生元素的value一致,外部操作可以更改組件屬性,是否需要監(jiān)聽屬性變化作出相應處理根據(jù)空間類型和業(yè)務進行斟酌;
4.一定要使用form表單提交功能去驗證,原生form 配合name和label
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
HTML5表單及其驗證
form HTML元素
一篇文章帶你了解Django Form組件(入門篇)
HTML5項目筆記2:離線系統(tǒng)表單設計
python測試開發(fā)django -143.Bootstrap 表單控件校驗狀態(tài)
任務7 使用Javascript實現(xiàn)驗證
更多類似文章 >>
生活服務
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服