在個人項目中,用戶點擊按鈕後,若是網頁響應慢一點,用戶常會再次點擊一下。結果就觸發了兩次 click 操做。 若是是查詢還好,但若是是post,put請求時,可能就是大問題了。javascript
因爲我用的是ng-zorro, 方案一是在組件中增長一個 isLoading=false 的變量, 按鈕上指定它的 nzLoading="isLoading" 。 zorro 文檔截圖: java
在click事件中: post
doSomeClick(){ this.isLoading=true; this.service.createxxxx().subscribe( ()=> this.isLoading=false ); }
問題:優化
一、頁面上若是有多個button話,且都綁定到一個isLoading變量, 則在點擊一個按鈕時,全部按鈕都禁用了。若是想每一個按鈕單獨控制,那就須要爲每一個按鈕分配一個變量,這樣會引入很是多的變量,也是麻煩事。this
利用throttleTime 來防止用戶兩次點擊,且但願用法改動很是小,好比
原來代碼: (click)="login()"
新代碼 : (click.once)="login()"spa
因此咱們實現一個 click.once的指令便可:code
import { Directive, Input, OnDestroy, OnInit, HostListener, Output, EventEmitter, Renderer2, ElementRef } from '@angular/core'; import { throttleTime } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs'; @Directive({ // tslint:disable-next-line:directive-selector selector: '[click.once]' }) export class OnceClickDirectiveDirective implements OnInit, OnDestroy { // tslint:disable-next-line:no-output-rename @Output('click.once') clickCall: EventEmitter<MouseEvent> = new EventEmitter(); @Input() duration = 2000; // 必須是數字,傳入時要用綁定語法 private $sub = new Subject<any>(); private subscription: Subscription; constructor( private renderer: Renderer2, // Angular 2.x導入Renderer private element: ElementRef ) { } ngOnInit() { // 如此綁定事件亦可 // this.renderer.listen( // this.element.nativeElement, 'click', event => { // event.preventDefault(); // event.stopPropagation(); // this.$sub.next(event); // } // ); this.subscription = this.$sub.pipe( throttleTime(this.duration) ).subscribe(e => { this.clickCall.emit(e); }); } @HostListener('click', ['$event']) clickEvent(event: MouseEvent) { event.preventDefault(); // 一般是不須要冒泡的 event.stopPropagation(); this.$sub.next(event); } ngOnDestroy() { this.subscription.unsubscribe(); } }
代碼裏的時間間隔設置2秒, 一般接口在這個時間內都能返回結果了。對象
優化:blog
一、這個實現沒有任何禁用狀態的效果, 用戶能夠連續點擊,不過只響應一次。
若是點擊後想產生遮罩層,能夠在根組件中添加一個變量控制這個層的顯示,而後引入一個全局的service來註冊一個Subject對象。當點擊時,就向subject對象emit() 一下,而後定時再清除遮罩層。
我懶得麻煩。就不添加了!接口