我的问题是,当我执行"双击"时,用于这两个事件的方法都会被触发
例如,我需要在触发特定事件时执行特定功能。
<a (click)="method1()" (dblclick)="method2()">
当我执行"双击"时,method1()
和method2()
都会被触发。
您可以使用超时和布尔标志来解决此问题。 请考虑以下事项:
DOM 需要几毫秒才能识别双击。
但可以肯定的是,它可以识别双击,但第一次单击也被识别。
所以逻辑是这样的。
isSingleClick: Boolean = true;
method1CallForClick(){
this.isSingleClick = true;
setTimeout(()=>{
if(this.isSingleClick){
doTheStuffHere();
}
},250)
}
method2CallForDblClick(){
this.isSingleClick = false;
doTheStuffDblClickHere();
}
在元素的单击事件中调用方法 1,在元素的单击事件中调用方法 2。
你可以将纯JavaScript回调dblclick
,或者像你在angular 2中用到的那样:(dblclick)="doubleClickFunction()"
。
如果在同一元素上同时具有(单击)和(dblclick),则应在单击事件回调中添加超时,以避免在用户双击时调用它。
尝试类似操作:
。.html:
<button (click)="singleClick()" (dblclick)="doubleClick()">click</button>
。.js:
singleClick(): void{
this.timer = 0;
this.preventSimpleClick = false;
let delay = 200;
this.timer = setTimeout(() => {
if(!this.preventSimpleClick){
...
}
}, delay);
}
doubleClick(): void{
this.preventSimpleClick = true;
clearTimeout(this.timer);
...
}
clickCount = 0;
click() {
this.clickCount++;
setTimeout(() => {
if (this.clickCount === 1) {
// single
} else if (this.clickCount === 2) {
// double
}
this.clickCount = 0;
}, 250)
}
这更干净
我找到了 RXJS 的解决方案,试试这个
我的模板有
<div #divElement></div>
我在我的组件中都有
@ViewChild('divElement') el: ElementRef;
ngAfterViewInit(): void {
this.handleClickAndDoubleClick();
}
handleClickAndDoubleClick(){
const el = this.el.nativeElement;
const clickEvent = fromEvent<MouseEvent>(el, 'click');
const dblClickEvent = fromEvent<MouseEvent>(el, 'dblclick');
const eventsMerged = merge(clickEvent, dblClickEvent).pipe(debounceTime(300));
eventsMerged.subscribe(
(event) => {
if(event.type === 'click'){
//click
}
//dblclick
}
);
我还没有找到在 Angular(或 Javascript)中原生执行此操作的方法,但这里有一种通用方法可以让它适用于所有点击处理程序。
虽然在概念上与其他答案相似,但其他答案不能很好地处理重复点击,并且不能在正确的时间维护(和重置!)它们的标志。
这里的想法是维护一个标志,用于在共享上下文(同一元素)的单击处理程序和 dblclick 处理程序之间做出决定:
- 单击处理程序等待一小段时间以排除双击
- 双击处理程序在该等待期内阻止单击处理程序
- 因为双击意味着两个单单击,所以双击时,再次等待一小段时间,然后再将标志切换回来,以确保第二次单击也被阻止
以下是您在示例中使用它的方式:
<a (click)="method1()" (dblclick)="method2()"></a>
在组件内部:
const clickContext = new ClickContext();
class YourComponent {
method1 = clickContext.clickHandler(() => { /* your method1 */ });
method2 = clickContext.dblClickHandler(() => { /* your method2 */ });
}
对于同时需要单击和 dblClick 处理程序的每个上下文(元素),都需要创建单独的上下文。幸运的是,这是一个罕见的要求。
现在,通过使用我将在下面介绍的魔术实用程序类,可以正确处理单击和双击。
下面是执行标志监视和处理程序执行的类:
export class ClickContext {
private isSingleClick = true;
clickHandler(handler: ClickHandler): ClickHandler {
return function() {
const args = arguments;
this.isSingleClick = true;
setTimeout(() => {
this.isSingleClick && handler.apply(undefined, args);
}, 250);
}
}
dblClickHandler(handler: ClickHandler): ClickHandler {
return function() {
const args = arguments;
this.isSingleClick = false;
setTimeout(() => {
this.isSingleClick = true;
}, 250);
handler.apply(undefined, args);
}
}
}
type ClickHandler = (...any) => void;
请注意,要注意确保将原始参数传递给目标事件处理程序方法 1 和 method2。
It needs simple work-round to block single click then do double click. Check this example
@Component({
selector: 'my-app',
template: `
<div>
<h2>{{title}}</h2>
<button (click)="singleClick($event)" (dblclick)="doubleClick( $event)"> Click </button>
</div>
`,
})
export class App {
title:string;
preventSingleClick = false;
timer: any;
delay: Number;
constructor() {
this.title = `Angular (click) and (dblclick)`
}
singleClick(event) {
this.preventSingleClick = false;
const delay = 200;
this.timer = setTimeout(() => {
if (!this.preventSingleClick) {
alert('Single Click Event');
}
}, delay);
}
doubleClick () {
this.preventSingleClick = true;
clearTimeout(this.timer);
alert('Double Click Event')
}
}
[普伦克][1]
[1]: http://plnkr.co/edit/pbsB0zYQCEY4xrPKngrF?p=preview
更新(Angular 13): 我在 angular 中创建了一个指令来处理单击和双击事件,希望这有助于它只是一个解决方法。它的工作原理取决于代码注释。(在评论部分开放改进) 🙂
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: '[doubleTap]',
})
export class DBLTapGestureDirective implements OnInit {
el: HTMLElement;
private lastOnStart: number = 0;
//double click threshold fires a double click event if there are 2 click within 230ms
private DOUBLE_CLICK_THRESHOLD: number = 230;
//single click threshold fires a single click after 250ms
// during this time is listening for another click to si if it is a double click
private SINGLE_CLICK_THRESHOLD: number = 250;
private isSingleClick: boolean = true;
//Emit Single and double click event
@Output() doubleTap = new EventEmitter<void>();
@Output() singleTap = new EventEmitter<void>();
constructor(el: ElementRef, private gestureCtrl: GestureController) {
this.el = el.nativeElement;
}
ngOnInit(): void {
//Create gesture
const gesture = this.gestureCtrl.create({
el: this.el,
threshold: 0,
gestureName: 'my-gesture',
onStart: () => {
//Start Listening
this.onStart();
},
});
gesture.enable();
}
private onStart(): void {
//get current time
let now = Date.now();
//check if time is within the double click threshold if not go to single click
if (Math.abs(now - this.lastOnStart) <= this.DOUBLE_CLICK_THRESHOLD) {
//emits double click event
this.doubleTap.emit();
//set single click false in order to not fire the single click event
this.isSingleClick = false;
//reset the last click timer
this.lastOnStart = 0;
//after the double click finished reset the single click to true to start listening again for single click
setTimeout(() => {
this.isSingleClick = true;
}, this.DOUBLE_CLICK_THRESHOLD);
} else {
//set a timeout before sending single click event to wait if there is a double click
setTimeout(() => {
if (this.isSingleClick) {
//fire single click event
this.singleTap.emit();
//set single click back to true
this.isSingleClick = true;
}
}, this.SINGLE_CLICK_THRESHOLD);
//set last click time to now to make the compare in the next click
this.lastOnStart = now;
}
}
}
<div
(doubleTap)="like()"
(singleTap)="openImage()"
class="message-container">Image</div>
这是我在角度中双击的方式
clickme()
{
this.count++;
if(count%2==0)
{ this.doubleclickme(); }
}
this.count is a global variable .
this.doubleclickme() is a an other function in the component .
与 https://stackoverflow.com/a/60877770/9970629 中的阿曼多类似的方法 - 但就我而言,我不太想使用ViewChild
.
此方法使用 ReplaySubject。本质上,我为单击事件定义了一个接口,并为所有收到的单击事件和双击事件定义了重播主题。然后,我将真正的单击(单击而不双击)定义为两者与去抖动的合并,以及仅发出单击的过滤器:
interface ClickRowEvent<T extends any = any> {
clickType: "single" | "double";
data: T;
}
@Component({
selector: "foo",
template: `
<div *ngFor let thing of things>
<div
(click)="handleSingleClick(thing)
(dblclick)="handleDoubleClick(thing)"
>
{{thing}}
</div>
</div>
`
})
export class MyComponent {
things = ["foo", "bar", "baz"];
private _singleClickEvents: ReplaySubject<ClickRowEvent>;
private singleClickEvents$: Observable<ClickRowEvent>;
private _doubleClickEvents: ReplaySubject<ClickRowEvent>;
private doubleClickEvents$: ReplaySubject<ClickRowEvent>;
constructor() {
this._singleClickEvents = new ReplaySubject<ClickRowEvent>();
this._doubleClickEvents = new ReplaySubject<ClickRowEvent>();
this.doubleClickEvents$ = this._doubleClickEvents.asObservable();
const allClicks$ = this._singleClickEvents.asObservable();
this.singleClickEvents$ = merge(allClicks$, this.doubleClickEvents$).pipe(
debounceTime(250),
filter((e) => e.clickType === "single")
);
}
handleSingleClick(data: T): void {
this._singleClickEvents.next({ clickType: "single", data });
}
handleDoubleClick(data: T): void {
this._doubleClickEvents.next({ clickType: "double", data });
}
}
现在,您可以订阅所有singleClickEvents$
和doubleClickEvents$
,而无需额外的状态管理。当然,如果您不想要额外的clickType
属性,您也可以映射回数据/事件。
您可以使用事件参数
网页模板:
<div (click)="showModal($event)"></div>
元件
showModal(e) {
if(e.detail == 2) {
//blabla...
}
}
我只是偶然发现了这个,但我不喜欢 setTimeout 的答案,因为单击的反应时间也会延迟。我想要对单击的即时反应,但要防止双击时发生两次单击事件。
我的情况很特殊,我也想处理单击。所以这可能并没有真正回答这个问题,因为我同时做 - 单击和双击 - 对我来说唯一的事情是,当双击触发时,我不执行第二个单击事件。
我的解决方案很简单,我只是测量两次点击之间花费的时间,如果它超过 500 毫秒(dblclick 的默认延迟),那么我将执行单击代码。 如果没有,则 dblclick 将触发,而第二次单击不会。
clicked = 0;
clickHandler() {
if (Date.now() - this.clicked > 500) { // change threshold as you need
this.clicked = Date.now();
// click logic here
}
}
dblClickHandler() {
// dblclick logic here, no extra code needed
}
itemClicked(event: MouseEvent) {
if (event.type == 'click') {
}
}
itemdblClicked(event: MouseEvent) {
if (event.type.toLowerCase() == 'dblclick') {
}
}