我有一个带有click
的组件。
<my-box (click)="openModal()"></my-box>
当我单击此元素时,将运行openModal
函数。
而且我想给1000ms节流时间,以防止打开多个模式。
我的第一种方法是使用Subject
(来自rxJs)
//html
<my-box (click)="someSubject$.next()"></my-box>
//ts
public someSubject$:Subject<any> = new Subject();
...etc subscribe
但是我觉得这有点冗长。
下一种方法是使用directive
。
我修改了通过谷歌搜索找到的一些代码。
//ts
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: '[noDoubleClick]'
})
export class PreventDoubleClickDirective {
constructor() {
}
@HostListener('click', ['$event'])
clickEvent(event) {
event.stopPropagation(); // not working as I expected.
event.preventDefault(); // not working as I expected.
event.srcElement.setAttribute('disabled', true); // it won't be working unless the element is input.
event.srcElement.setAttribute('style', 'pointer-events: none;'); // test if 'pointer-events: none' is working but seems not.
setTimeout(function () {
event.srcElement.removeAttribute('disabled');
}, 500);
}
}
//html
<my-box noDoubleClick (click)="openModal()"></my-box>
但是,无论我如何尝试,总是执行openModal
。
我找不到如何停止执行指令中的openModal
。
我可以像
//ts
//In the openModal method.
openModal() {
public isClickable = true
setTimeout(() => {
this.newsClickable = true;
}, 1000);
...
}
但是对于可重用的代码,我认为使用指令是理想的选择。
我该怎么做?
答案 0 :(得分:12)
您可以使用RxJs的debounce或debounceTime运算符来防止双击。 Here还是有关如何创建自定义去抖动点击指令的帖子。
以防将来删除帖子,这是最终代码:
import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit,
Output } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import { debounceTime } from 'rxjs/operators';
@Directive({
selector: '[appDebounceClick]'
})
export class DebounceClickDirective implements OnInit, OnDestroy {
@Input()
debounceTime = 500;
@Output()
debounceClick = new EventEmitter();
private clicks = new Subject();
private subscription: Subscription;
constructor() { }
ngOnInit() {
this.subscription = this.clicks.pipe(
debounceTime(this.debounceTime)
).subscribe(e => this.debounceClick.emit(e));
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
@HostListener('click', ['$event'])
clickEvent(event) {
event.preventDefault();
event.stopPropagation();
this.clicks.next(event);
}
}
<button appDebounceClick (debounceClick)="log()" [debounceTime]="700">Debounced Click</button>
答案 1 :(得分:4)
在我的情况下,throttleTime
而不是去抖动是更好的解决方案(立即触发事件并在一段时间之前阻止)
答案 2 :(得分:3)
由于有人要求使用throttleTime
指令,因此我将其添加到下面。我之所以选择这条路线,是因为debounceTime
等待最后的点击,然后才触发实际的点击事件。 throttleTime
将不允许点击器在该时间之前再次单击该按钮,而是立即触发click事件。
import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
@Directive({
selector: '[appPreventDoubleClick]'
})
export class PreventDoubleClickDirective implements OnInit, OnDestroy {
@Input()
throttleTime = 500;
@Output()
throttledClick = new EventEmitter();
private clicks = new Subject();
private subscription: Subscription;
constructor() { }
ngOnInit() {
this.subscription = this.clicks.pipe(
throttleTime(this.throttleTime)
).subscribe(e => this.emitThrottledClick(e));
}
emitThrottledClick(e) {
this.throttledClick.emit(e);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
@HostListener('click', ['$event'])
clickEvent(event) {
event.preventDefault();
event.stopPropagation();
this.clicks.next(event);
}
}
throttleTime
是可选的,因为指令中的默认值为500
<button appPreventDoubleClick (throttledClick)="log()" [throttleTime]="700">Throttled Click</button>
如果您的漫游器每1毫秒点击一次元素,那么您会注意到该事件只会触发一次,直到throttleTime
触发为止。
答案 3 :(得分:1)
我为按钮提出了一种更简单的方法:
import {Directive, ElementRef, HostListener} from '@angular/core';
const DISABLE_TIME = 300;
@Directive({
selector: 'button[n-submit]'
})
export class DisableButtonOnSubmitDirective {
constructor(private elementRef: ElementRef) { }
@HostListener('click', ['$event'])
clickEvent() {
this.elementRef.nativeElement.setAttribute('disabled', 'true');
setTimeout(() => this.elementRef.nativeElement.removeAttribute('disabled'), DISABLE_TIME);
}
}
用法示例:
<button n-submit (click)="doSomething()"></button>
答案 4 :(得分:0)
还是想防止多次单击按钮?我正在使用以下解决方案:
import { Directive, HostListener } from '@angular/core';
@Directive({
selector: '[disableAfterClick]'
})
export class DisableButtonAfterClickDirective {
constructor() { }
@HostListener('click', ['$event'])
clickEvent(event) {
event.preventDefault();
event.stopPropagation();
event.currentTarget.disabled = true;
}
}
我不知道它是否是最有效,最优雅的,但是它可以工作。
答案 5 :(得分:0)
我会使用自定义指令。
将其放在模板中的某个位置:
<button appSingleClick (singleClick)="log()" [throttleMillis]="1000">click</button>
SingleClickDirective 指令
import {Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output} from '@angular/core';
import {fromEvent, Subscription} from 'rxjs';
import {throttleTime} from 'rxjs/operators';
@Directive({
selector: '[appSingleClick]'
})
export class SingleClickDirective implements OnInit, OnDestroy {
private subscription: Subscription;
@Input()
throttleMillis = 1500;
@Output()
singleClick = new EventEmitter();
constructor(private elementRef: ElementRef) {
}
ngOnInit(): void {
this.subscription = fromEvent(this.elementRef.nativeElement, 'click')
.pipe(throttleTime(this.throttleMillis))
.subscribe((v) => {
this.singleClick.emit(v);
});
}
ngOnDestroy(): void {
this.subscription?.unsubscribe();
this.singleClick.unsubscribe();
}
}
答案 6 :(得分:0)
下面的代码对我有用,可以防止双击。
onClick(event) {
const button = (event.srcElement.disabled === undefined) ? event.srcElement.parentElement : event.srcElement;
button.setAttribute('disabled', true);
setTimeout(function () {
button.removeAttribute('disabled');
}, 1000);
//Your code}
和 HTML:
<button class="btn btn-save" (click)="onClick($event)">
Prevent Double click
</button>