在个人项目中,用户点击按钮后,若是网页响应慢一点,用户常会再次点击一下。结果就触发了两次 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() 一下,而后定时再清除遮罩层。
我懒得麻烦。就不添加了!接口