为什么/何时在iOS上需要点击两次才能触发点击

42

好的,我感觉自己有点疯了...

我正在使用iOS 6.0上的移动Safari浏览器。似乎不能确定点击元素何时会触发click事件。在许多情况下,似乎我需要点击一次才能触发hover效果,再点击一次才能触发click事件。

Mobile Safari规范中写道:"......由一个手指和两个手指手势生成的事件流取决于所选元素是否可点击或可滚动......可点击元素是链接、表单元素、图像映射区域或具有mousemove、mousedown、mouseup或onclick处理程序的任何其他元素......由于这些差异,您可能需要将一些元素更改为可点击元素......"

文档还建议开发者“......添加一个虚拟的onclick处理程序,即onclick=“void(0)”,以便Safari在iOS上将span元素识别为可点击元素。”

但是,我的测试结果表明这些说法是错误的。

JsFiddle:http://jsfiddle.net/6Ymcy/1/

html

<div id="plain-div" onclick="void(0)">Plain Div</div>

JavaScript

document.getElementById('plain-div').addEventListener('click', function() {
   alert('click'); 
});

尝试在iPad上点击元素,没有反应

但我偏离了主题。 对我来说重要的是找出以下问题:

究竟是什么标准决定了在第一次点击元素时会触发“click”事件? 而不是在第一次点击时触发“hover”事件,第二次点击时触发“click”事件。

在我的测试中,锚点元素是我唯一可以偶尔和不一致地在第一次点击时触发点击的元素。

这就是我开始感到疯狂的地方。 我搜遍了互联网,几乎没有关于这个问题的任何信息。 就只有我吗?! 有人知道是否有讨论过两次点击的标准或处理这些限制的方法吗?

我很乐意回答问题/请求。

谢谢!


是的,苹果的onclick建议仍然无法正常工作(iOS模拟器):-( - Simon H
12个回答

14

我曾经遇到过同样的问题。最简单的解决方案是不要在iOS (或任何触摸设备平台)上绑定mouseenter事件。如果没有绑定,将不会触发悬停事件,而click事件会在第一次点击时触发。


12

iOS将在元素在普通状态下具有“display:none”,并在:hover状态下具有“display:block”或“inline-block”时触发悬停事件。


3
我为此奋斗了数个小时,寻找其他无数问题。在我的情况下,我使用Angular的ng-switch和ng-show来显示/隐藏元素(通过改变显示CSS值),这导致iOS不能触发点击事件的奇怪问题。 - Ryan
哇,这真的很难找到。谢谢! - Konrad G

4
值得一提的是,':hover' 伪类可能会阻止 'click' 事件的触发。
在移动浏览器中,点击有时用于替换悬停操作(例如显示下拉菜单),它们可能在第一次点击时触发人工 'hover' 状态,然后在第二次点击时处理点击。
请参见 https://css-tricks.com/annoying-mobile-double-tap-link-issue/ 获取详细说明和示例。

3

我在使用Bootstrap时遇到了这个问题,后来发现罪魁祸首是工具提示。如果从按钮中移除工具提示,你就不需要再次点击它了。


3

我通过首先检测是否为iPhone,然后绑定mouseup事件到我想要调用的函数来解决了这个问题。

if ((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))){ 
    $('foo').on('mouseup', function(){
        ...
    }
}

我尝试了其他事件,但是mouseup似乎效果最好。其他事件例如touchend即使用户想要滚动页面时也会触发。如果您在触摸后拖动手指,则mouseup事件不会被触发。

感谢David Walsh(和ESPN)提供的iPhone检测方法。 http://davidwalsh.name/detect-iphone


这似乎已经为我解决了问题 - 谢谢。 - ChrisFox

1
我的解决方案是从CSS中移除:hover状态。如果你想在桌面端保留:hover状态,可以使用媒体查询,如下所示:
.button {
    background: '#000'
}

@media (min-width: 992px) {
    .button:hover {
        background: '#fff'
    }
}

1

您需要使用@media (hover) { /* 您的样式 */ }

据我所知,这个问题在各种形式上仍然存在。

2019年,大多数情况下,如果不是所有情况,都可以通过仅使用CSS的解决方案来改善... 但是,这将需要一些样式表重构。

label {
  opacity:0.6  
}

label input[type=radio]:checked+span {
  opacity:1
}

.myClass::before { } /* Leave me empty to catch all browsers */

a:link { color: blue }
a:visited { color: purple }
a:hover { } /* Leave me empty to catch all browsers */
a:active { font-weight: bold }



/* Your styles */
@media (hover) {
  a:hover { color: red }

  .myClass::before { background: black }

  label:hover {
    opacity:0.8
  }
}

您可以在这里详细了解为什么使用@media (hover)可以修复Fastclick:pseudo<span>、仅针对"桌面"分辨率以及第一次点击是悬停,第二次点击是单击的问题: https://css-tricks.com/annoying-mobile-double-tap-link-issue/ :hover不再像以前那样提供清晰的样式输入,触摸式桌面和移动设备对此概念有着不同的解释。

0

上面提到的display:none;解决方案适用于iOS(未在9.3.5之后测试),但不适用于Android。

一个hacky的纯CSS解决方案是使用负z-index隐藏元素下面的链接,并在:hover或first-touch(带有小的过渡延迟)时将链接提升到正z-index。我猜可以使用CSS translate而不是z-index来实现相同的结果。适用于iOS和Android。

通过这种方式,您可以在触摸屏设备上的第一次点击中显示链接的悬停效果,而不会在第二次点击之前激活URL。


如果它不能在Android上运行,那就不是一个好的解决方案。 - basZero

0
你可以在元素上使用ontouchstart事件代替onclick事件,并在此元素上调用函数focus()(如果它是输入框)。
document.getElementById('plain-div').addEventListener('touchstart', function() {
   //write body of your function here
    alert(“hi”);
  // if input needs double tap 
  this.focus();

});

-1

我从来没有弄清楚标准,但是这个方法解决了我的问题,只要元素被轻敲,就会立即触发点击事件:

https://developers.google.com/mobile/articles/fast_buttons

我不得不对他们的代码进行多次添加/修改,才能使其正常工作。如果您对我的方法感兴趣,我会尝试发布一份说明。

谢谢 :)


4
我使用FastClick JS Polyfill解决了这个问题——https://github.com/ftlabs/fastclick - JohnA10
此链接已失效。 - random_user_name
@cale_b: http://web.archive.org/web/20140326101523/https://developers.google.com/mobile/articles/fast_buttons - Davi Lima

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