【angular】primeng源码分析,⾃定义表单元素checkbox组件,实现ngMo。。
背景:最近项⽬准备使⽤angular7,想快速⼊⼿,最好的⽅式就是⾃⼰动⼿封装⼀些常⽤的组件,在此可以直接参考primeng,重构⼀些常⽤的组件。
⽬的:封装⼀个checkbox组件
废话不多说,跟着下⾯的步骤,完整的跑通⼀个组件的开发。
checkboxponent.html
<div
[ngStyle]="style"
[ngClass]="'app-chkbox app-widget'"
[class]="styleClass">
<div class="app-helper-hidden-accessible">
<input #cb type="checkbox"
[attr.id]="inputId"
[name]="name"
[value]="value"
[checked]="checked"
[disabled]="disabled"
(focus)="onFocus($event)"
(blur)="onBlur($event)"
[ngClass]="{'app-state-focus':focused}"
(change)="handleChange($event)"
[attr.tabindex]="tabindex">
</div>
<div class="app-chkbox-box app-widget app-corner-all app-state-default"
(click)="onClick($event,cb,true)"
[ngClass]="{'app-state-active':checked,'app-state-disabled':disabled,'app-state-focus':focused}">
<span class="app-chkbox-icon app-clickable"
[ngClass]="{'pi pi-check':checked}"></span>
</div>
</div>
<label
(click)="onClick($event,cb,true)"
[class]="labelStyleClass"
[ngClass]="{'app-chkbox-label': true, 'app-label-active':checked, 'app-label-disabled':disabled, 'app-label-focus':focused}"
*ngIf="label"
[attr.for]="inputId">{{label}}</label>
注解:
输⼊属性 @Input():根据需求配置;
ngClass控制样式的显⽰和移除;
事件(eventName):重点就是onClick事件;
HTML attribute 和 DOM property的区别;
checkboxponent.scss
$activeColor: #007ad9;
$normalColor: #a6a6a6;
$hoverColor: #212121;
.app-chkbox{
cursor: pointer;
display: inline-block;
vertical-align: middle;
margin-right: .25em;
user-select: none;
.app-chkbox-box{
border: 1px solid $normalColor;
background-color: #fff;
width: 20px;
height: 20px;
line-height: 20px;
border-radius: 2px;
text-align: center;
border-radius: 3px;
transition: background-color .2s, border-color .2s, box-shadow .2s;
&.app-state-active{
border-color: $activeColor;
background-color: $activeColor;
}
&:not(.app-state-disabled):hover{
border-color: $hoverColor;
}
}
.app-chkbox-icon{
display: block;
}
}
.app-chkbox-label{
vertical-align: middle;
}
基础样式,不够完整,⽤⼼的同学可以⾃⾏补全;
checkboxponent.ts
import{ Component, OnInit, EventEmitter, ChangeDetectorRef, forwardRef, OnChanges, SimpleChanges, Input, Output }from'@angular/core'; import{ ControlValueAccessor,NG_VALUE_ACCESSOR, FormControl }from'@angular/forms';
@Component({
selector:'app-checkbox',
templateUrl:'./checkboxponent.html',
styleUrls:['./checkboxponent.scss'],
providers:[{
provide:NG_VALUE_ACCESSOR,
useExisting:forwardRef(()=> CheckboxComponent),
multi:true
}]
})
export class CheckboxComponent implements OnInit, ControlValueAccessor {
@Input() name: string;
@Input() value: any;
@Input() label: string;
@Input() disabled: boolean;
@Input() binary: boolean;
@Input() tabindex: number;
@Input() inputId: string;
@Input() style: any;
@Input() styleClass: string;
@Input() labelStyleClass: string;
@Output() change: EventEmitter<any>;
formControl: FormControl;
checked: boolean;
focused: boolean;
model: any;
onModelChange: Function;
onModelTouched: Function;
constructor(
private cd: ChangeDetectorRef
)
{
this.change =new EventEmitter<any>();
this.focused =false;
this.checked =false;
}
ngOnInit(){
}
/**
* template模板源事件
* @param event 组件
* @param cb 表单元素
* @param focus 触发focus事件
*/
onClick(event: Event, checkbox: HTMLInputElement, focus: boolean):void{    event.preventDefault();
if(this.disabled){
return;
}
this.checked =!this.checked;
this.updateModel();
if(focus){
checkbox.focus();
}
}
/**
* 更新model
*/
updateModel(){
if(!this.binary){
if(this.checked){
this.addValue();
}else{
}
if(this.formControl){
this.formControl.del);// 触发writeValue
}
}else{
}
it(this.checked);// 外部获取的event事件
}
addValue(){
del){
}else{
}
}
removeValue(){
return item !==this.value;onblur和blur的区别
});
}
handleChange(event: any){
this.checked = event.target.checked;
this.updateModel();
}
isChecked(){
if(this.binary){// 允许返回boolean值
del;
}else{
del &&del.indexOf(this.value)>-1;
}
}
// 触发更新-内部状态
onFocus(event){
this.focused =true;
}
onBlur(event){
this.focused =false;
}
// Angular API 和 DOM 元素之间的桥梁
writeValue(model){
this.checked =this.isChecked();
this.cd.markForCheck();
}
registerOnChange(fn: any){
}
registerOnTouched(fn: any){
}
setDisabledState(val: boolean){
this.disabled = val;
}
}
重点说明:
providers:[{
provide:NG_VALUE_ACCESSOR,
useExisting:forwardRef(()=> CheckboxComponent),
multi:true
}]
组件类定义,providers声明,provide是必须的,Used to provide a ControlValueAccessor for form controls。
interface ControlValueAccessor {
writeValue(obj: any):void
registerOnChange(fn: any):void
registerOnTouched(fn: any):void
setDisabledState(isDisabled: boolean)?:void
}
Defines an interface that acts as a bridge between the Angular forms API and a native element in the DOM
定义⼀个接⼝,作为Angular表单API和DOM中的原⽣元素之间的桥梁
正是因为它,才实现了Angular ngModel及其form表单的接⼝
这⾥不多赘述,可以参考⽂档
基础概念需要提前熟悉:EventEmitter,Input,Output, FormControl等等
组件类的⽅法遵循基本原则:
⽐如,单⼀性,拆得越细越好,⼀个⽅法就⼲⼀件事,便于复⽤:
更新值,创建 addValue
移除值, 创建removeValue
调⽤组件测试效果
docponent.html
<form [formGroup]="myFormGroup"(ngSubmit)="onSubmit()">
<div>
<h3 class="first">Basic</h3>
<div class="ui-g" >
<div class="ui-g-12"><app-checkbox value="New York"[formControl]="ls['checkList']"label="New York"[(ngModel)]="checkbox List"inputId="ny"></app-checkbox></div>
<div class="ui-g-12"><app-checkbox value="San Francisco"[formControl]="ls['checkList']"name="chbox"label="San Francisco "[(ngModel)]="checkboxList"inputId="sf"></app-checkbox></div>
<div class="ui-g-12"><app-checkbox value="Los Angeles"[formControl]="ls['checkList']"name="chbox"label="Los Angeles"[(n gModel)]="checkboxList"inputId="la"></app-checkbox></div>
</div>
<p [hidden]="ls['checkList'].valid || (ls['checkList'].pristine)"class="alert alert-danger">
这是⼀个必填项
</p>
Selected Cities: <span *ngFor="let city of checkboxList" >{{city}}</span>
</div>
<p>
Form Value: {{ myFormGroup.value | json }}
</p>
<p>
Form Status: {{ myFormGroup.status }}
</p>
<p>
<button type="button"[ngStyle]="{'margin-right': '5px'}"(click)="setNormalValue()">setNormalValue</button>
<button type="submit"[disabled]="myFormGroup.invalid">Submit</button>
</p>
</form>
1. myFormGroup 检测,整个表单,可以把这个对象打印出来看结构;
2. 验证基础要懂,⼏个常⽤的状态值: valid, invalid, pending, pristine, dirty , untouched, touched;
docponent.ts

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。