我正在开发一个需要在多种设备上运行的移动网站。目前让我头疼的是黑莓手机。
我们需要同时支持键盘点击和触摸事件。
理想情况下,我会使用:
$thing.click(function(){...})
但我们遇到的问题是,一些黑莓设备从触摸到触发点击有一个非常恼人的延迟。
补救方法是使用touchstart:
$thing.bind('touchstart', function(event){...})
但是如何绑定两个事件,但只触发一个事件呢?对于键盘设备,我仍然需要click事件,但当然,如果我使用的是触摸设备,我不想让click事件触发。
一个额外的问题:有没有办法做到这一点,并额外适应那些甚至没有touchstart事件的浏览器?在研究中,看起来黑莓OS5不支持touchstart,因此也需要依赖于该浏览器的点击事件。
附录:
也许一个更全面的问题是:
使用jQuery,是否可能/建议使用相同的绑定同时处理触摸交互和鼠标交互?
理想情况下,答案是肯定的。如果不是,我确实有一些选择:
我们使用WURFL来获取设备信息,这样就可以创建我们自己的设备矩阵。根据设备的不同,我们将使用touchstart或click。
通过JS检测浏览器中的触摸支持(我需要做更多的研究,但这似乎是可行的)。
然而,还有一个问题:支持这两种功能的设备怎么办?我们支持的一些手机(即诺基亚和黑莓)既有触摸屏又有键盘。这让我又回到了最初的问题……有没有一种方法可以同时兼顾两者?
编辑:我之前的答案(基于这篇文章中的答案)并不适合我。我想要一个子菜单展开鼠标进入或触摸点击和折叠鼠标离开或另一次触摸点击。由于鼠标事件通常是在触摸事件之后触发的,因此编写同时支持触摸屏和鼠标输入的事件侦听器有点棘手。
jQuery插件:触摸或鼠标
我最终写了一个jQuery插件“Touch Or Mouse”(压缩897字节),可以检测一个事件是由触摸屏还是鼠标调用的(不需要测试触摸支持!)这样可以同时支持触摸屏和鼠标,并完全分离它们的事件。
通过这种方式,OP可以使用touchstart或touchend来快速响应触摸单击,并使用click来响应仅由鼠标调用的单击。
示范
第一个是ie。body元素跟踪触摸事件:
$(document.body).touchOrMouse('init');
鼠标事件以默认方式和调用$body来绑定元素。touchOrMouse('get', e)我们可以发现事件是由触摸屏还是鼠标调用的。
$('.link').click(function(e) {
var touchOrMouse = $(document.body).touchOrMouse('get', e);
if (touchOrMouse === 'touch') {
// Handle touch click.
}
else if (touchOrMouse === 'mouse') {
// Handle mouse click.
}
}
查看插件在http://jsfiddle.net/lmeurs/uo4069nh上的工作。
解释
This plugin needs to be called on ie. the body element to track touchstart and touchend events, this way the touchend event does not have to be fired on the trigger element (ie. a link or button). Between these two touch events this plugin considers any mouse event to be invoked by touch.
Mouse events are fired only after touchend, when a mouse event is being fired within the ghostEventDelay (option, 1000ms by default) after touchend, this plugin considers the mouse event to be invoked by touch.
When clicking on an element using a touchscreen, the element gains the :active state. The mouseleave event is only fired after the element loses this state by ie. clicking on another element. Since this could be seconds (or minutes!) after the mouseenter event has been fired, this plugin keeps track of an element's last mouseenter event: if the last mouseenter event was invoked by touch, the following mouseleave event is also considered to be invoked by touch.
这里没有提到,但你可能想看看这个链接:https://joshtronic.com/2015/04/19/handling-click-and-touch-events-on-the-same-element/
为了便于后人回顾,您可以简单地检查设备是否是触摸屏并仅分配给相关事件,而不是尝试分配给两个处理程序然后对结果进行排序。观察:
var clickEvent = (function() {
if ('ontouchstart' in document.documentElement === true)
return 'touchstart';
else
return 'click';
})();
// and assign thusly:
el.addEventListener( clickEvent, function( e ){
// things and stuff
});
我使用它来绑定我的事件,这样我就可以在触摸屏上测试,处理touchstart和click事件,会触发两次,在我的开发PC上只听到点击
不过,该链接的作者提到了一个问题,即设计用于处理这两种事件的触摸屏笔记本电脑:
I learned about a third device I was not considering, the touchscreen laptop. It’s a hybrid device that supports both touch and click events. Binding one event means only that event be supported. Does that mean someone with a touchscreen and mouse would have to explicitly touch because that’s the only event I am handling?
Binding touchstart and click seemed ideal to handle these hybrid devices. To keep the event from firing twice, I added e.stopPropagation() and e.preventDefault() to the callback functions. e.stopPropagation() stops events from “bubbling up” to their parents but also keeps a second event from firing. I included e.preventDefault() as a “just in case” but seems like it could be omitted.