【问题标题】:Preventing ghost click when binding 'touchstart' and 'click'绑定'touchstart'和'click'时防止鬼点击
【发布时间】:2013-11-26 18:33:39
【问题描述】:

我正在开发一个应用,在我的桌面和移动设备上进行测试。我正在尝试修复移动设备上这些缓慢的按钮按下,并且刚刚了解了 touchstart 和 click 之间的区别。

所以我用 jquery 绑定我的按钮来执行 touchstart 和 click 像这样:

$('.button').on('touchstart click', function(){
});

现在该应用在手机上的表现稍好一些。但是,它执行的是触摸点击,然后是常规点击,即可能双击,或者当下一张幻灯片进入时,它点击那里的某些东西。在我的情况下,出现了一个表单,并且选择了出现在单击按钮的空间中的输入字段。鬼点击。

如何告诉我的函数,如果有触摸,则忽略点击?

或者更好的是,有没有办法告诉 jquery 只承认所有“点击”为触摸?

我会删除“点击”绑定,但是我无法在我的桌面环境中如此轻松地进行完全测试。

【问题讨论】:

    标签: jquery mobile


    【解决方案1】:

    如果您想为不同的事件类型做特定的事情,请使用e.type

    $('.button').on('touchstart click', function(e) {    
        e.preventDefault(); //prevent default behavior
        if(e.type == "touchstart") {
            // Handle touchstart event.
        } else if(e.type == "click") {
            // Handle click event.
        }
    });
    

    【讨论】:

    • @willdanceforfun - 很高兴为您提供帮助。
    • 这不会阻止点击事件在 Firefox 中触发(到目前为止我只测试过一个)。它只是两者兼而有之,如果您希望在移动设备中获得与在桌面浏览器中相同的行为,它仍然会执行该操作两次。
    • 请注意 - 此解决方案不适用于三星浏览器(因此在操作系统版本低于 4.4 的设备的 Webview 中,它将触发这两个事件)
    • e.stopPropagation() 不会阻止触发第二个事件。 e.preventDefault() 可以解决问题。
    • e.stopPropagation() 将如何停止第二个事件?它和e.preventDefault() 一样,只处理当前事件,这里我们将有两个独立的事件。
    【解决方案2】:

    Touchstart 应该在单击之前发生,因此如果事件是 touchstart 类型,我将删除单击处理程序。这似乎对我的目的很有效:

    $('.do-popdown').on('click touchstart', handlePopdown);
    function handlePopdown(e){
        if(e.type == 'touchstart') {
            $('.do-popdown').off('click', handlePopdown).click(function(e){
                // do nothing
                e.stopPropagation();
                e.preventDefault();
                return false;
            });
        }
        // do my handling...
        // and nothing else:
        e.stopPropagation();
        e.preventDefault();
        return false;
    }
    

    e.stopPropagation(); e.preventDefault(); return false; 可能有点矫枉过正,但我​​将它用于各种不同的元素(<a><div><span><button> 等),这满足了我的日常需求。

    编辑:更通用(更好?)的方法是创建类似于熟悉的.click() 事件绑定器的东西:

    jQuery.fn.extend({
        clickOrTouch: function(handler) {
            return this.each(function() {
                var event = ('ontouchstart' in document) ? 'touchstart' : 'click';
                $(this).on(event, handler);
            });
        }
    });
    

    这样,只有适当的事件附加到选定的元素。

    我想一个更“正确”的名称应该是 .touchstartOrClick(),但由于它或多或少是 .click() 的替代品,我决定以 click 开头。

    这可以像.click() 一样使用。例如,将 button 放在 div 内并运行:

    $('button').clickOrTouch(doSomething);
    $('div').clickOrTouch(doSomething);
    function doSomething(e) {
        $('body').append(this.tagName + ' ' + e.type + '<br>');
        e.stopPropagation();
    }
    

    这将根据触发方式显示“DIV click”或“BUTTON touchstart”。如果在链接上使用它,请在您的处理程序中添加 e.preventDefault()(如果需要)。

    【讨论】:

    • 乍一看还不错!有时间我得试试这个。我实际上有点放弃了我正在走的路,但毫无疑问,我会回来的。
    • 请注意,对于同时具有鼠标和触摸事件之类的设备,仅检测设备上的触摸事件是不够的,并且由于触摸而取消绑定点击事件可能会禁用鼠标点击。
    • 您永远不应该为touchstartclick 附加处理程序,因为某些设备会同时具备:一个用于使用触摸屏时,另一个用于使用鼠标/触控板时。
    【解决方案3】:

    @Krishna 的这段代码对我不起作用:

    $('.button').on('touchstart click', function(e) {    
        e.stopPropagation(); //stops propagation
        if(e.type == "touchstart") {
            // Handle touchstart event.
        } else if(e.type == "click") {
            // Handle click event.
        }
    });
    

    但正如@Slashback 最初建议的那样,这个应该可以工作。

    $('.button').on('touchstart click', function(e) {    
        e.preventDefault();
    
        if(e.type == "touchstart") {
            // Handle touchstart event.
        } else if(e.type == "click") {
            // Handle click event.
        }
    });
    

    .preventDefault() 单独为我工作,而不是 .stopPropagation()。我也不必过度杀戮。

    【讨论】:

    • 这似乎更像是一个评论而不是一个答案。
    【解决方案4】:

    我正在使用 PhoneGap。这可能会有所帮助:

    function longTapEvent(id, longTapFun) {
        $(id).click(function() {
            longTapFun();
            return;
        })
    
        $(id).unbind("touchstart");
        $(id).bind("touchstart", function() {
            //do sth...
        });
        $(id).unbind("touchend");
        $(id).bind("touchend", function() {
            //do sth...
        });
    }
    

    【讨论】:

      【解决方案5】:

      如果之前的触发不是点击(即触摸或其他),您可以检测点击并转义当前触发的功能 - 在 vanilla js 中:

      buttonx.addEventListener('touchend',clicktap);
      buttonx.addEventListener('click',clicktap);
      
      function clicktap(e) {
      var c = e.type.includes("click"); // or "mouse" if using "mousedown"
      if (c && (this.wastouched)) return this.wastouched = 0;
      this.wastouched = !c;
      
      // ..run things..
      
      }
      

      【讨论】:

        【解决方案6】:

        这是我自己的自制解决方案,请批评一下!谢谢!

        基本上,如果您点击价格按钮,商品会立即添加到购物车中。

        如果您点击/触摸按钮,它会显示价格。 点击/触摸第二次,商品被添加到购物车。

        在此处查看实际操作:https://www.indospace.io/studio-city/urban-treez

            var price_button = $(evt.target).closest('.price-button')
            if(price_button.length) {
                price_button.on('mouseleave', function() {
                    $(this).removeAttr('data-touched')
                })
                if(evt.type == 'touchstart') {
                    jQuery.touch_start = true
                    if(!price_button.attr('data-touched')) {
                        price_button.attr('data-touched', 1)
                        return
                    }
                    price_button.attr('data-touched', 2)
                }
                if(evt.type == 'click') {
                    if(price_button.attr('data-touched'))
                        return
                }
                bag.add(price_button)
                return true
            }
        

        【讨论】:

          【解决方案7】:

          如果目的是区分用户拖动和点击,那么使用 touchmove 而不是 touchstart 的 vanilla JS 适用于我:

           document.querySelector("#mydiv").addEventListener("click", function(e){
              console.log("click");
           });
           let count = 0;
           document.querySelector("#mydiv").addEventListener("touchmove", function(e){
              e.preventDefault();
          
              // if need to detect once
              //count++;
              //if(count == 3){
              //  console.log("dragged!");  // dragHandler(), and reset count later
              //}
          
              console.log("touchmove");
           });
          

          更多信息:https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent

          【讨论】:

            【解决方案8】:

            我在我的项目中使用以下内容:

            $('.button').on('touchstart', function() {
            
               var thisButton = $(this); 
               if(!thisButton.hasClass('disabled')) {
                 thisButton.addClass('disabled'); //add class disabled to prevent double execution
            
                 ............rest of code
            
                 window.setTimeout(function () {
                    thisButton.removeClass('disabled'); //remove class disalbed after 300ms
                 }, 300);
            
            });
            

            我希望这会对某人有所帮助。

            【讨论】:

              【解决方案9】:

              在元素上使用 data-tap-disabled="true" 解决了我的问题。

              http://ionicframework.com/docs/api/page/tap/

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-12-28
                • 2011-10-24
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多