我正在开发一个需要在多种设备上运行的移动网站。目前让我头疼的是黑莓手机。

我们需要同时支持键盘点击和触摸事件。

理想情况下,我会使用:

$thing.click(function(){...})

但我们遇到的问题是,一些黑莓设备从触摸到触发点击有一个非常恼人的延迟。

补救方法是使用touchstart:

$thing.bind('touchstart', function(event){...})

但是如何绑定两个事件,但只触发一个事件呢?对于键盘设备,我仍然需要click事件,但当然,如果我使用的是触摸设备,我不想让click事件触发。

一个额外的问题:有没有办法做到这一点,并额外适应那些甚至没有touchstart事件的浏览器?在研究中,看起来黑莓OS5不支持touchstart,因此也需要依赖于该浏览器的点击事件。

附录:

也许一个更全面的问题是:

使用jQuery,是否可能/建议使用相同的绑定同时处理触摸交互和鼠标交互?

理想情况下,答案是肯定的。如果不是,我确实有一些选择:

我们使用WURFL来获取设备信息,这样就可以创建我们自己的设备矩阵。根据设备的不同,我们将使用touchstart或click。 通过JS检测浏览器中的触摸支持(我需要做更多的研究,但这似乎是可行的)。

然而,还有一个问题:支持这两种功能的设备怎么办?我们支持的一些手机(即诺基亚和黑莓)既有触摸屏又有键盘。这让我又回到了最初的问题……有没有一种方法可以同时兼顾两者?


当前回答

找到文档滚动移动的差异(水平和垂直)touchstart和touchend,如果其中一个大于1像素,那么它是移动而不是单击

var touchstartverscrollpos , touchstarthorscrollpos;


    $('body').on('touchstart','.thumbnail',function(e){

        touchstartverscrollpos = $(document).scrollTop();
        touchstarthorscrollpos = $(document).scrollLeft();


    });



    $('body').on('touchend','.thumbnail',function(e){


        var touchendverscrollpos = $(document).scrollTop();
        var touchendhorscrollpos = $(document).scrollLeft();

        var verdiff = touchendverscrollpos - touchstartverscrollpos;
        var hordiff = touchendhorscrollpos - touchstarthorscrollpos;


        if (Math.abs(verdiff) <1 && Math.abs(hordiff)<1){

// do you own function () here 



            e.stopImmediatePropagation();

            return false;
        }

    });

其他回答

出于文档的目的,以下是我所能想到的最快/响应最快的桌面点击/移动点击解决方案:

我用一个修改过的函数替换了jQuery的on函数,只要浏览器支持触摸事件,就用touchstart替换了我所有的点击事件。

$.fn.extend({ _on: (function(){ return $.fn.on; })() });
$.fn.extend({
    on: (function(){
        var isTouchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
        return function( types, selector, data, fn, one ) {
            if (typeof types == 'string' && isTouchSupported && !(types.match(/touch/gi))) types = types.replace(/click/gi, 'touchstart');
            return this._on( types, selector, data, fn);
        };
    }()),
});

than的用法和以前完全一样,比如:

$('#my-button').on('click', function(){ /* ... */ });

但它会在可用时使用touchstart,在不可用时使用click。不需要任何形式的延误:D

为事件赋值'touchstart mousedown'或'touchend mouseup'可能会很有效,以避免使用click所产生的不必要的副作用。

我发现的最好方法是编写touch事件,并让该事件以编程方式调用正常的click事件。这样你就有了所有正常的点击事件,然后你只需要为所有的触摸事件添加一个事件处理程序。对于每一个你想要使其可触摸的节点,只需向其添加“touchable”类来调用触摸处理程序。用Jquery,它的工作原理是这样的,有一些逻辑,以确保它是一个真正的触摸事件,而不是一个假阳性。

$("body").on("touchstart", ".touchable", function() { //make touchable  items fire like a click event
var d1 = new Date();
var n1 = d1.getTime();
setTimeout(function() {
    $(".touchable").on("touchend", function(event) {
        var d2 = new Date();
        var n2 = d2.getTime();
        if (n2 - n1 <= 300) {
            $(event.target).trigger("click"); //dont do the action here just call real click handler
        }
    });
}, 50)}).on("click", "#myelement", function() {
//all the behavior i originally wanted
});

如果你正在使用jQuery,下面的工作对我来说很好:

var callback; // Initialize this to the function which needs to be called

$(target).on("click touchstart", selector, (function (func){
    var timer = 0;
    return function(e){
        if ($.now() - timer < 500) return false;
        timer = $.now();
        func(e);
    }
})(callback));

其他解决方案也很好,但我在一个循环中绑定多个事件,需要自调用函数来创建适当的闭包。此外,我不想禁用绑定,因为我希望它可以在下次单击/触摸启动时调用。

可能会帮助到有类似情况的人!

为什么不使用jQuery事件API?

http://learn.jquery.com/events/event-extensions/

我成功地使用了这个简单的事件。它干净、可命名且足够灵活,可以继续改进。

var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var eventType = isMobile ? "touchstart" : "click";

jQuery.event.special.touchclick = {
  bindType: eventType,
  delegateType: eventType
};