触摸事件触发两次

8

我在移动设备/平板电脑上遇到事件触发两次的问题。当我点击下面的函数时,应该下拉的菜单会下拉,然后立即向上滑动。这只是在触摸设备上出现的问题。

$(document).on("touchend click", ".lines-button", function(e){

    e.stopImmediatePropagation();
    if($(this).hasClass("close")){
        $(this).removeClass("close");
        $(".widget1x1Back").next(".actionsHolder3").slideUp("fast", function() {
            $(this).remove();
        });             
    }else{

        var iconsList = $(this).closest(".top1x1").next(".hdnActnLst").find(".iconsHolder3").html();
        $(this).closest(".widget1x1").append(iconsList);
        $(this).closest(".widget1x1").find(".actionsHolder3").hide();
        $(this).closest(".widget1x1").find(".actionsHolder3").slideDown(700,"easeOutBack");
        $(this).addClass("close");
    }
});

任何输入都很好,谢谢!

尝试添加一个警告(alert( e.type );),告诉你触发函数的事件类型。我有一种感觉,你的函数会被触发两次(一次是touchend,一次是click)。参考 - JRulle
@JRulle 是的!那似乎就是问题所在,有没有一种方法可以通用地处理点击和触摸事件?谢谢! - ajmajmajma
3个回答

13

你遇到的问题是你的函数被触发了两次(每个事件类型都会触发一次)。 在此DEMO中可以查看。(我现在正在使用mousedownclick,因为我在桌面上,但原理是相同的)。

你需要捕获和处理对该事件的重复调用。你可以尝试设置一个handled布尔值,以便click事件知道touch事件是否处理了该事件(应该首先触发触摸事件)。就像这样...

var handled = false;
$(document).on("touchend click", ".lines-button", function(e){
    e.stopImmediatePropagation();

    if(e.type == "touchend") {
        handled = true;
        handleIt();
    }
    else if(e.type == "click" && !handled) {
        handleIt();
    }
    else {
        handled = false;
    }
});

function handleIt() { 
        if($(this).hasClass("close")){
            $(this).removeClass("close");
            $(".widget1x1Back").next(".actionsHolder3").slideUp("fast", function() {
                $(this).remove();
            });             
        }else{

            var iconsList = $(this).closest(".top1x1").next(".hdnActnLst").find(".iconsHolder3").html();
            $(this).closest(".widget1x1").append(iconsList);
            $(this).closest(".widget1x1").find(".actionsHolder3").hide();
            $(this).closest(".widget1x1").find(".actionsHolder3").slideDown(700,"easeOutBack");
            $(this).addClass("close");  
        } 
}

这里有一个更新的 codepen.io,展示了事件跳过逻辑。 - JRulle
我认为你的代码需要更新。它仍然使用“e.event”,但应该使用“e.type”,因为“e.event”返回未定义。 - Leo

12

在大多数情况下,以下代码将是可行的:

$(document).on("touchend click", ".lines-button", function(e){
    if(e.type == 'touchend'){
        $(this).off('click');
    }
});

如果touchend可用,您可以放弃使用click


这是一个非常干净的解决方案。 - griffla
1
这只是一个很好的解决方案,如果你只对第一次点击感兴趣的话。否则,你必须一遍又一遍地重新建立监听器。 - agoldev
@agoldev,刚刚测试了一下,它会丢失事件。 - Leo

0

以下是对@JRules答案的轻微修改,对我很有效

// lo is just a global object holder 
let lo = {
    "handled":false
}

使用委托是因为对象在原始页面加载时没有加载

$('body').delegate('.linkRow','click touchend',function(e) {  //   
    e.stopPropagation();
    if(lo.handled === false){  // check
        doSomething()                 
        lo.handled = true
    }
    setTimeout(() => {  // now set to false later (example here is 1/2 sec)
        lo.handled = false
    }, 500)
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接