iPad上的touchend事件会被调用两次,造成了点击事件的重复。

17

我正在使用jQuery的animate方法来实现幻灯片效果。在幻灯片的末尾我放了一个箭头,并给它绑定了点击事件。点击箭头时,其工作原理是将幻灯片中的一个项目移动一次,并在鼠标按下时移动整个幻灯片。在桌面上运行良好,但在iPad上,每次点击时会有两个项目进入幻灯片。我不明白为什么iPad上会调用两次点击事件。以下是点击事件的示例代码:

    $('#next_item').bind('mousedown touchstart MozTouchDown',function(e) {                    
        $('.slide').animate({left:left},6000);   
    });

    $('#next_item').bind('mouseup touchend MozTouchRelease',function(e) {   
        No.nextItem();          
    });

#next_item是指幻灯片末尾箭头的ID。我已经尝试过unbind touchstarttouchend事件,但在滑动幻灯片时,由于解绑定,单个项目不会进入幻灯片中。No.nextItem()将幻灯片内的一个项目向前移动。在$('.slide')中的left表示向左移动幻灯片。请帮我找到解决这个问题并解决iPad上的问题的方法。

3个回答

42

iPad同时支持touchstart/-end和mousestart/-end事件。

它们的触发方式如下:

┌─────────────────────┬──────────────────────┬─────────────────────────┐
│Finger enters tablet │ Finger leaves tablet │ Small delay after leave │
├─────────────────────┼──────────────────────┼─────────────────────────┤
│touchstart           │ touchend             │ mousedown               │
│                     │                      │ mouseup                 │
└─────────────────────┴──────────────────────┴─────────────────────────┘
你需要检测用户是否在平板电脑上,并依靠触摸开始的事情...:
/********************************************************************************
* 
* Dont sniff UA for device. Use feature checks instead: ('touchstart' in document) 
*   The problem with this is that computers, with touch screen, will only trigger 
*   the touch-event, when the screen is clicked. Not when the mouse is clicked.
* 
********************************************************************************/
var isIOS = ((/iphone|ipad/gi).test(navigator.appVersion));
var myDown = isIOS ? "touchstart" : "mousedown";
var myUp = isIOS ? "touchend" : "mouseup";

然后像这样绑定它:

$('#next_item').bind(myDown, function(e) { 
你还可以创建一个处理它的事件,参见: http://benalman.com/news/2010/03/jquery-special-events/ 基本归一化下事件:
$.event.special.myDown = {
    setup: function() {
        var isIOS = ((/iphone|ipad/gi).test(navigator.appVersion));
        var myDown = isIOS ? "touchstart" : "mousedown";
        $(this).bind(myDown + ".myDownEvent", function(event) {
            event.type = "myDown";
            $.event.handle.call(this, event);
        });
    },
    teardown: function() {
        $(this).unbind(".myDownEvent");
    }
};

在jQuery 1.9.0之后,$.event.handle 的名称已更改为$.event.dispatch,为了同时支持两者,您可以使用以下回退方法:

// https://dev59.com/3nDXa4cB1Zd3GeqP9S64
// ($.event.dispatch||$.event.handle).call(this, event);
$.event.special.myDown = {
    setup: function() {
        var isIOS = ((/iphone|ipad/gi).test(navigator.appVersion));
        var myDown = isIOS ? "touchstart" : "mousedown";
        $(this).bind(myDown + ".myDownEvent", function(event) {
            event.type = "myDown";
            ($.event.dispatch||$.event.handle).call(this, event);
        });
    },
    teardown: function() {
        $(this).unbind(".myDownEvent");
    }
};

1
将touchstart命令映射替换为mouseclick命令时要小心。您会失去click事件的一个非常有价值的功能。点击后跟随touchmove会取消click操作。touchstart后跟随touchmove将触发touch/click事件,无论是否存在touchmove事件。因此,如果您意外地点击了某个元素,则不能将手指从该元素上拖动以取消点击。 - Alex
6
在触摸事件处理程序中返回 false 会阻止鼠标事件的触发。 - Glenn Sandoval
最好使用H Dog的回答或Modernizr来测试事件是否存在。 - rachel
@rachel 我只使用用户代理进行检查的原因是我不想在答案中添加比必要更多的代码,以免“污染”它。 - Andreas Louv
1
像这样的代码要小心。Windows Surface支持触摸事件,同时也支持鼠标。如果用户正在使用鼠标,则触摸事件将永远不会触发。 - Chris
显示剩余4条评论

23

使用UA嗅探器检测iPad/iPod时要小心。这样的解决方案会忽略所有Android设备!更好的解决方案是检测触摸支持,它将适用于所有移动/平板设备:

var isTouchSupported = "ontouchend" in document;

2
问题在于支持鼠标和键盘,同时也有触摸屏的计算机将支持该事件,但只有在点击屏幕时才会触发。 - Andreas Louv

0

扩展 H Dog 的答案。这是适合我的代码。

 if (isTouchSupported) {
    $('#playanimationbtn').off("mouseup");
    $('#stopanimationbtn').off("mouseup");
    $('#playanimationbtn').off("mousedown");
    $('#stopanimationbtn').off("mousedown");
    $('#playanimationbtn').off("click");
    $('#stopanimationbtn').off("click");
    document.getElementById("playanimationbtn").addEventListener("touchend", PlayAnimation);
    document.getElementById("stopanimationbtn").addEventListener("touchend", StopAnimation);
} else {
    $('#playanimationbtn').off("touchstart");
    $('#playanimationbtn').off("touchend");
    $('#playanimationbtn').off("touchmove");
    $('#playanimationbtn').off("touchend");
    $('#playanimationbtn').off("touchleave");
    $('#stopanimationbtn').off("touchstart");
    $('#stopanimationbtn').off("touchend");
    $('#stopanimationbtn').off("touchmove");
    $('#stopanimationbtn').off("touchend");
    $('#stopanimationbtn').off("touchleave");
    document.getElementById("playanimationbtn").addEventListener("click", PlayAnimation);
    document.getElementById("stopanimationbtn").addEventListener("click", StopAnimation);
}

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