我正在尝试使用 JavaScript 和 jQuery 来捕获触摸事件。但我在 Android 2.3.2 上的 Web 浏览器中看到了一些非常奇怪的行为:每当我点击屏幕,然后快速点击屏幕上的其他位置时,浏览器:
- 瞬间显示橙色边框并在整个屏幕上突出显示,并且
- 向我发送错误的事件。
橙色边框似乎只是同一个潜在问题的相关症状,所以我并不太担心——它实际上可以方便地判断浏览器何时搞砸了。我真正想知道的是,我怎样才能始终如一地获得两次快速点击的正确触摸事件?我相信当这个问题解决后,橙色边框也会消失。
以下是我迄今为止制定的所有痛苦细节。
这是一个显示问题的页面,并显示了许多有关接收到的每个事件的详细信息和时间的诊断信息。如果您在蓝色矩形内点击,您肯定会收到橙色闪光/不良事件,然后在黑色矩形内快速点击。
我的 jQuery 代码非常标准。函数的log
实现并不重要;问题是浏览器没有在它应该调用它的时候调用它。
el = $('#battle');
el.on('touchstart', function(event) {
log(event);
return event.preventDefault();
});
el.on('touchend', function(event) {
return log(event);
});
el.on('touchcancel', function(event) {
return log(event);
});
el.mousedown(function(event) {
log(event);
return event.preventDefault();
});
return el.mouseup(function(event) {
return log(event);
});
关于我最初描述的现象的更多细节:
橙色边框和高亮:这与单击超链接时浏览器围绕超链接绘制的橙色边框和高亮相同。但是页面上没有超链接,并且浏览器在整个屏幕周围绘制了这个橙色边框——或者更具体地说,在<div id="battle">
我通过 jQuery 挂钩事件的外部周围。
错误的事件:在我的touchstart
事件处理程序中,我调用event.preventDefault()
, 告诉浏览器不要滚动,不要合成鼠标事件等。因此,我希望只获取touchstart
和touchend
事件。我这样做了,第一次点击。但是,第二次点击时,我得到的不是touchstart
/ ,而是触摸事件、合成鼠标事件的所有组合,以及第二次点击的偶然事件,甚至是第一次点击的重复事件。详情如下。touchend
touchcancel
这种行为也只发生在非常特殊的情况下:
- 第一个抽头必须很短(小于~200ms)。
- 此后第二次轻敲必须很快到来(在第一次轻敲之后小于~450ms
touchstart
)。 - 第二个抽头必须距离第一个抽头至少 150 像素(从第一个抽头的坐标沿对角线测量
touchstart
)。 - 如果我删除了挂钩
mousedown
和mouseup
的代码,橙色矩形将不再出现。但是,触摸事件有时仍然会出现乱码。
至于我所说的事件被乱码的意思,这就是我所看到的。当我写“1:”时,这意味着事件是针对第一个点击的坐标;“2:”表示第二次点击的坐标。我看到了以下事件模式(百分比表示每个事件在 100 次试验后出现的次数):
- (50%) 1:touchstart 1:touchend 1:mousedown 1:mouseup (短延迟) 2:mousedown 2:mouseup
- (35%) 1:touchstart 1:touchend 2:touchstart 1:mousedown 1:mouseup 2:touchend
- (10%) 1:touchstart 1:touchend 2:touchstart 1:mousedown 1:mouseup 2:touchcancel (短延迟) 2:mousedown 2:mouseup
- (3%) 1:touchstart 1:touchend 2:touchstart 2:touchend (短延迟) 1:mousedown 1:mouseup
- (2%) 1:touchstart 1:touchend 1:mousedown 1:mouseup (第二次点击什么也没有)
某些事件组合似乎更频繁地出现,具体取决于我点击的速度,但我还没有完全确定模式。(在上面的第二项下似乎更有可能出现两次快速、清脆的敲击声,而不太强调脆度的更快速的方法似乎更有可能是第一项。但我还没有确定导致领先的具体时间数字到每个人。)类似地,上面指出的“短延迟”可以是〜150ms到〜400ms的任何地方;我也没有对整个模式进行逆向工程。
如果我不钩mousedown
and mouseup
,分布大致是这样的:
- (40%) 1:touchstart 1:touchend 2:touchstart 2:touchcancel
- (35%) 1:touchstart 1:touchend 2:touchstart 2:touchend (实际期望的行为)
- (25%) 1:touchstart 1:touchend (第二次点击什么都没有)
因此,如果我不挂钩鼠标事件,它会在三分之一的时间内起作用;如果我愿意假装这touchcancel
意味着与 相同的东西touchend
,我可以得到高达 75% 的时间。但这仍然很糟糕。
我已经尝试过的替代方案:
- 我尝试过使用jQuery Mobile和events
vmousedown
,vmouseup
但它们并不总是在第二次点击时触发,我怀疑是因为同样的潜在事件怪异。 - 我可以完全忘记触摸事件,只使用合成的鼠标事件,但是在物理点击和合成鼠标事件的传递之间通常有大约半秒的延迟,而触摸事件是即时的,所以我可以更快地响应. 我还想防止滚动——这是针对全屏游戏的,我不希望用户不小心将地址栏滚动回视图并阻止游戏的一部分——并且
preventDefault
通常touchstart
可以实现这一点(尽管偶尔尽管我的第二个水龙头实际上能够滚动屏幕preventDefault
......我想解决整个事件混乱的另一个原因)。 - 我尝试过第三方 Web 浏览器 ( Dolphin ),但它与事件有同样的问题。所以我猜这可能是底层 WebView 将事件传递给脚本的方式存在问题。
任何人都可以建议一种方法来更改我的 HTML、我的事件处理程序或其他任何东西,以便连续两次快速点击可靠地获取触摸事件?