分享一個最近寫的支持表單驗證的時間選擇組件。數組
import {AfterViewInit, Component, forwardRef, Input, OnInit, Renderer} from "@angular/core"; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms"; @Component({ selector: 'time-picker', template: ` <div id="container"> <input id="input_box" readonly [(ngModel)]="_value" [ngStyle]="{'width.px': inputWidth, 'height.px': inputHeight}" (click)="onInputClick($event)" (focus)="onInputFocus($event)" (blur)="onInputBlur()"> <div id="panel" *ngIf="showBox"> <div class="ui-g"> <div class="ui-g-4 title">小時</div> <div class="ui-g-8 title">分鐘</div> </div> <div class="ui-g"> <div class="ui-g-4"> <span class="item" *ngFor="let hour of hours" [ngClass]="{'selected': hour == selectedHour}" (click)="onHourClick(hour, $event)">{{hour}}</span> </div> <div class="ui-g-8"> <span class="item" *ngFor="let minute of minutes" [ngClass]="{'selected': minute == selectedMinute}" (click)="onMinuteClick(minute, $event)">{{minute}}</span> </div> </div> </div> </div> `, styles: [` :host{ display: inline-block; } #container{ position: relative; } #input_box{ outline: none; box-sizing: border-box; padding: 0 3px; } #panel{ position: absolute; width: 400px; background-color: white; box-shadow: 0 2px 8px 4px rgba(0,0,0,0.2); z-index: 2000; } .title{ text-align: center; } .item{ display: inline-block; width: 30px; height: 30px; line-height: 30px; text-align: center; cursor: pointer; } .item:hover, .item.selected{ background-color: #0b7dd8; color: white; } `], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TimePicker), // 此時TimePicker未聲明,所以須要使用forwardRef multi: true } ] }) export class TimePicker implements ControlValueAccessor, OnInit, AfterViewInit{ // ControlValueAccessor,一座表單控件和原生元素或自定義輸入組件之間的橋樑 @Input() inputWidth = 100; // 輸入框寬度 @Input() inputHeight = 30; // 輸入框高度 _value: string; showBox = false; // 控制選擇面板顯示與否,true爲顯示 hours = []; // 小時數組 minutes = []; // 分鐘數組 hourIsSelect = false; // 打開選擇面板後,標記小時是否被點擊 minIsSelect = false; // 打開選擇面板後,標記分鐘是否被點擊 selectedHour; // 當前小時 selectedMinute; // 當前分鐘 bodyClickListener: any; constructor( public renderer: Renderer ){} ngOnInit(){ for(let i = 0; i < 24; i++){ let h; if(i < 10){ h = '0' + i; }else{ h = '' + i; } this.hours.push(h); } for(let j = 0; j < 60; j++){ let m; if(j < 10){ m = '0' + j; }else{ m = '' + j; } this.minutes.push(m); } } ngAfterViewInit(){ this.bodyClickListener = this.renderer.listenGlobal('body','click', () => { this.hide() }); } onChange = (time: string) => {}; onTouched = () => {}; get value(): string{ return this._value; } set value(val: string){ if(val !== this._value){ this._value = val; this.onChange(val); } } /** * 實現ControlValueAccessor中的方法,用於將model顯示到view * @param val */ writeValue(val: string): void{ if(val !== this._value){ this._value = val; } if(this._value){ let time = this._value.split(':'); this.selectedHour = time[0]; this.selectedMinute = time[1]; } } /** * 實現ControlValueAccessor中的方法,用於通知Angular值已被修改 * @param fn */ registerOnChange(fn: (time: string) => void): void{ this.onChange = fn; } /** * 實現ControlValueAccessor中的方法,用於通知Angular輸入框被鼠標聚焦過 * @param fn */ registerOnTouched(fn: () => void): void{ this.onTouched = fn; } /** * 隱藏選擇面板 */ hide(){ this.showBox = false; this.hourIsSelect = false; this.minIsSelect = false; } /** * 顯示選擇面板 */ show(){ this.showBox = true; } /** * 輸入框得到焦點 * @param event */ onInputFocus(event){ event.stopPropagation(); this.show(); } /** * 輸入框失去焦點 */ onInputBlur(){ this.onTouched(); } /** * 輸入框點擊 * @param event */ onInputClick(event){ event.stopPropagation(); } /** * 選擇小時 * @param h * @param event */ onHourClick(h, event){ event.stopPropagation(); this.selectedHour = h; this.value = this.selectedHour + ':' + (this.selectedMinute ? this.selectedMinute : '00'); this.hourIsSelect = true; if(this.hourIsSelect && this.minIsSelect){ this.hide(); } } /** * 選擇分鐘 * @param min * @param event */ onMinuteClick(min, event){ event.stopPropagation(); this.selectedMinute = min; this.value = (this.selectedHour ? this.selectedHour : '00') + ':' + this.selectedMinute; this.minIsSelect = true; if(this.hourIsSelect && this.minIsSelect){ this.hide(); } } }