分享一個最近寫的支持表單驗證的時間選擇組件。 import {AfterViewInit, Component, forwardRef, Input, OnInit, Renderer} from "@angular/core"; import {ControlValueAccessor, NG_V ...
分享一個最近寫的支持表單驗證的時間選擇組件。
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();
}
}
}