解讀elementui的組件源碼,angular select2源碼解析_Angular 組件庫 NG-NEST 源碼解析:Form 表單組件

 2023-10-08 阅读 19 评论 0

摘要:前言NG-NEST介紹今天我們來看一下 Form 表單組件是如何實現的:解讀elementui的組件源碼、功能分析由不同的表單控件組成(輸入框、選擇器、單選框、多選框等)控件的禁用、必填、正則驗證等狀態標題和控件位置,局部分類,柵格布局等代碼分析l

前言

NG-NEST介紹

今天我們來看一下 Form 表單組件是如何實現的:

解讀elementui的組件源碼、

486f72e4ee84dc64f98759aacd307f55.png

功能分析

  • 由不同的表單控件組成(輸入框、選擇器、單選框、多選框等)
  • 控件的禁用、必填、正則驗證等狀態
  • 標題和控件位置,局部分類,柵格布局等

代碼分析

lib/ng-nest/ui/form
├── docs                        md 文檔
├── examples                    示例
├── style                       樣式 @mixin 和 樣式參數定義
├── control.component.html      
├── control.component.ts        控件組件(映射不同類型的表單組件)
├── form.component.html        
├── form.component.scss
├── form.component.ts
├── form.component.spec.ts      測試文件,測試模式下直接訪問對應的關鍵子調試單個組件
├── form.module.ts              組件模塊,聲明模塊中的視圖,依賴的模塊,以及導出的視圖
├── form.property.ts            組件屬性( Input 輸入和 Ouput 輸出參數),以及相關的類型定義,文檔中的組件參數說明通過此處生成
├── index.ts
├── package.json                ng-packagr 配置,單獨引入組件
└── public-api.ts               組件文件以及API

我們先看 form.component.html 文件:

<!-- 
使用 formGroup 指令指定一個表單對象,并指定相關樣式 
controlsType 用來區分 controls 中是否包含了行的分類,通過 ngSwitch 來指定不同的模板 
-->
<form#formclass="x-form"[formGroup]="formGroup"[style.width]="width"[style.padding-bottom.rem]="controlsType === 'controls' ? this.space : 0"[ngClass]="classMap"
><ng-container [ngSwitch]="controlsType"><ng-container *ngSwitchCase="'controls'"><ng-container *ngTemplateOutlet="controlsTemp; context: { controls: controls }"> </ng-container></ng-container><ng-container *ngSwitchCase="'rows'"><ng-container *ngTemplateOutlet="rowsTemp; context: { rows: controls }"></ng-container></ng-container></ng-container>
</form><!-- 
行模板,先加載行分類,在加載行中對應的控件
通過行參數 hidden 可以隱藏整行 
-->
<ng-template #rowsTemp let-rows="rows"><ng-container *ngFor="let row of rows"><x-row [hidden]="row.hidden"><ng-container *ngTemplateOutlet="titleTemp; context: { row: row }"></ng-container><ng-container *ngTemplateOutlet="controlsTemp; context: { controls: row.controls }"></ng-container></x-row></ng-container>
</ng-template><!-- 行中控件 -->
<ng-template #controlsTemp let-controls="controls"><x-row [space]="space"><x-col[style.padding-top.rem]="space"[span]="!control.span ? span : control.span"*ngFor="let control of controls"[hidden]="control.hidden"><x-control [option]="control"></x-control></x-col></x-row>
</ng-template><!-- 行標題模板 -->
<ng-template #titleTemp let-row="row"><label class="x-form-title"><x-icon *ngIf="row.icon" [type]="row.icon"></x-icon><span>{{ row.title }}</span></label>
</ng-template>

對應的 form.component.ts 文件:

export class XFormComponent extends XFormProperty implements OnInit {// 用來判斷傳遞的控件參數中是否包含行controlsType: 'controls' | 'rows';// 用來存儲所有的控件組件controlComponents: { [property: string]: XFormControlComponent } = {};// 用來存儲所有的控件類型controlTypes: { [property: string]: XFormControlType } = {};constructor(public cdr: ChangeDetectorRef, public configService: XConfigService) {super();}ngOnChanges(changes: SimpleChanges) {XIsChange(changes.disabled) && this.setDisabled();}ngOnInit() {this.setControls();this.setClassMap();}ngAfterViewInit() {this.setDisabled();}setControls() {if (this.controls && this.controls.length > 0) {this.controlsType = this.controls[0].controls ? 'rows' : 'controls';}}setClassMap() {this.classMap[`${XFormPrefix}-${this.controlsType}`] = true;}// 通過表單禁用/啟用所有控件,并處理相關的必填、正則驗證setDisabled() {if (Object.keys(this.controlComponents).length === 0) return;if (this.disabled) {for (let key in this.controlComponents) {let [control, type] = [this.controlComponents[key], this.controlTypes[key]];control.disabled = true;control.required = false;delete control.pattern;type.setValidators();control.formControlChanges();}} else {for (let key in this.controlComponents) {let [control, type] = [this.controlComponents[key], this.controlTypes[key]];control.disabled = type.disabled as XBoolean;control.required = type.required as XBoolean;control.pattern = type.pattern as RegExp | RegExp[];type.setValidators();control.formControlChanges();}}this.formGroup.updateValueAndValidity();}// 獲取表單中控件的驗證信息getValidatorMessages(): string[] {let result: string[] = [];if (this.formGroup.valid) return result;else {const eachControls = (array: XFormControlOption[]) => {for (const ctr of array) {const formCtr = this.formGroup.controls[ctr.id] as XFormControl;if (formCtr && formCtr.invalid) {result = [...result, ...(formCtr.messages as string[])];}}};if (this.controlsType === 'rows') {for (const row of this.controls as XFormRow[]) {eachControls(row.controls);}} else {eachControls(this.controls as XFormControlOption[]);}}return result;}
}

element源碼、form 組件主要是用來組織表單結構,并提供了全局禁用的方式以及獲取驗證信息的方法。

接下來我們看控件組件 control.component.html :

 <div class="x-control" [formGroup]="form?.formGroup"><ng-container [ngSwitch]="option?.control"><ng-container *ngSwitchCase="'input'"><x-input [formControlName]="option.id" (clearEmit)="option.clearClick && option.clearClick($event)"></x-input></ng-container><ng-container *ngSwitchCase="'select'"><x-select [formControlName]="option.id"></x-select></ng-container>......<ng-container *ngSwitchCase="'find'"><x-find [formControlName]="option.id"></x-find></ng-container></ng-container>
</div>
  • form 對應我們的表單父組件
  • 使用 ngSwitch 來指定不同的組件
  • 在使用各種組件的時候只定義了 formControlName 的名字,并且只對輸出參數做了處理,輸入參數在對應的 ts 文件里面直接映射進去
export class XControlComponent extends XControlProperty implements OnInit, AfterViewInit, OnDestroy {// 控件參數@Input() option: XFormControlOption;// 通過 FormControlName 獲取對應的控件@ViewChild(FormControlName, { static: false }) control: FormControlName;// 共享屬性,可以通過表單參數只指定一次,單個控件中不需要再指定private _sharedProps = ['span', 'direction', 'justify', 'align', 'labelWidth', 'labelAlign'];// 改變的屬性,此處可以調用參數中的 change 事件來觸發組件的更新 private _changeProps = ['label', ...this._sharedProps];// 控件類型private _control: XFormControlType;// 驗證類型private _validatorFns: ValidatorFn[] = [];private _unSubject = new Subject();// 根據 option 創建的 FormControl 對象 private _formControl: FormControl;constructor(@Host() @Optional() public form: XFormComponent, public cdr: ChangeDetectorRef, public configService: XConfigService) {super();}ngOnInit() {// 共享屬性設置this.setProps();// label 后綴設置this.option.label = `${this.option.label}${this.form.labelSuffix}`;// 創建控件類型this._control = this.createControl(this.option);// 創建控件對象this._formControl = new FormControl(this._control.value);// 驗證設置this.setValidators();// 訂閱狀態變化事件,用來設置顯示信息(主要正則驗證或錯誤信息)this._formControl.statusChanges.pipe(takeUntil(this._unSubject)).subscribe((x) => {this.setMessages(x);});// 定義類型中的驗證事件this._control.setValidators = () => this.setValidators();// formGroup 中添加表單對象this.form.formGroup.addControl(this._control.id, this._formControl);// 定義參數中的 change 事件this.option.change = () => {this._changeProps.forEach((x: string) => {if (this.control.valueAccessor && this.option[x]) {(this.control.valueAccessor as any)[x] = this.option[x];}});this.form.controlComponents[this._control.id].formControlChanges();};}ngAfterViewInit() {// 映射具體控件中的輸入參數// valueAccessor 指向我們事件的表單控件對象,比如 XInputComponent、XSelectComponentObject.assign(this.control.valueAccessor, this._control);// 把當前控件注冊到 form 父組件中,并執行對應組件改變事件this.form.controlTypes[this._control.id] = this._control;this.form.controlComponents[this._control.id] = this.control.valueAccessor as XFormControlComponent;this.form.controlComponents[this._control.id].formControlChanges();}ngOnDestroy() {this._unSubject.next();this._unSubject.unsubscribe();}// 控件驗證setValidators() {this._validatorFns = [];// 禁用if (this._control.disabled || this.form.disabled) {this._formControl.disable();} else {this._formControl.enable();}// 必填if (this._control.required && !this.form.disabled) {this._validatorFns = [...this._validatorFns, Validators.required];}// 正則if (this._control.pattern) {this.setPattern();}// 重新設置并更新驗證信息this._formControl.setValidators(this._validatorFns);this._formControl.updateValueAndValidity();}// 設置共享屬性setProps() {for (let prop of this._sharedProps) {if (XIsEmpty(this.option[prop])) this.option[prop] = (this.form as any)[prop];}}// 設置正則驗證setPattern() {if (Array.isArray(this._control.pattern)) {for (const pt of this._control.pattern) {this._validatorFns = [...this._validatorFns, Validators.pattern(pt)];}} else {this._validatorFns = [...this._validatorFns, Validators.pattern(this._control.pattern as RegExp)];}}// 設置正則驗證的信息getPatternMsg(pattern: string) {if (Array.isArray(this._control.pattern)) {return (this._control.message as Array<any>)[this._control.pattern.findIndex((x) => String(x) === pattern)];} else {return this._control.message;}}setMessages(state: 'INVALID' | 'VALID' | 'DISABLED') {let control: XFormControl = this._formControl;if (state === 'INVALID' && this._formControl.errors !== null) {for (const key in control.errors) {if (key === 'required') {control.messages = [`${this._control.label} 必填`];} else if (key === 'pattern') {control.messages = [`${this._control.label} ${this.getPatternMsg(control.errors[key].requiredPattern)}`];}}} else if (state === 'VALID') {control.messages = [];}}// 創建對應類型的控件createControl(option: XFormControlOption) {switch (option.control) {case 'input':return new XInputControl(option as XInputControlOption);case 'select':return new XSelectControl(option as XSelectControlOption);case 'checkbox':return new XCheckboxControl(option as XCheckboxControlOption);case 'radio':return new XRadioControl(option as XRadioControlOption);case 'switch':return new XSwitchControl(option as XSwitchControlOption);case 'rate':return new XRateControl(option as XRateControlOption);case 'date-picker':return new XDatePickerControl(option as XDatePickerControlOption);case 'time-picker':return new XTimePickerControl(option as XTimePickerControlOption);case 'input-number':return new XInputNumberControl(option as XInputNumberControlOption);case 'slider-select':return new XSliderSelectControl(option as XSliderSelectControlOption);case 'cascade':return new XCascadeControl(option as XCascadeControlOption);case 'color-picker':return new XColorPickerControl(option as XColorPickerControlOption);case 'find':return new XFindControl(option as XFindControlOption);default:return new XInputControl(option as XInputControlOption);}}
}

總結

以上就是 Form 表單組件的解析,控件組件主要用來映射具體的表單組件(輸入框、選擇框、多選框、單選框等),并在此基礎上提供了通用屬性以及方法。

小程序組件源碼、下一次將介紹 國際化 實現原理:

aee17832c8317c7603e9db2a3eaa37d2.gif

歡迎 Star 了解最新信息

https://github.com/NG-NEST/ng-nest?github.com

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/2/128884.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息