移动版Safari有时无法触发点击事件。

25

我正在开发一个动态的JavaScript应用程序。我有许多带有类的<a>锚元素,当点击这些类时应该触发某些事件。在Firefox、Chrome和IE中,这个功能都能正常工作,但是在移动版Safari(iPad和iPhone)中在某些情况下点击事件不会被触发。

这些元素都具有完全相同的CSS样式,只是它们的位置不同(它们位于不同的容器中)。

我尝试了在此处找到的各种解决方案,但都没有成功。例如:

你有任何其他想法可以帮助我找到解决方案吗?为什么在某些情况下只有点击事件会触发?


您应该使用href属性以确保锚点的正常工作。在 JavaScript 中使用.preventDefault() 来抵消其行为。 - Kyle
谢谢 Kyle。已添加 href,但没有成功。其他可用的元素也没有 href。我应该如何正确使用 .preventDefault()? - watt
该应用程序使用jQuery,因此在其点击函数中有.preventDefault()。 - watt
8个回答

36

在iOS上,由轻触产生的单击事件只有在特定条件下才会像预期的那样冒泡 - 其中之一就是您提到的光标样式。这里有另一个条件:

目标元素或其祖先(但不包括)中的任何一个为任何鼠标事件设置了显式事件处理程序。此事件处理程序可以是空函数。

http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html

这是更好的修复方法,可以在不进行浏览器检查的情况下完成。由于“不包括”部分,您必须添加额外的

<body>
  <div onclick="void(0);">
    <!-- ... all your normal body content ... -->
  </div>
</body>

现在,位于该 div 内部的每个点击事件都会像预期的那样在 iOS 中冒泡(这意味着您可以使用 $(document).on('click', '.class', etc...) 捕获它们)。


4
我会选择 body { cursor:pointer; }。许多代码将动态元素插入到 body 中,我不想修改它们所有的代码。 - deerchao
@deerchao 它不会对其他浏览器产生副作用吗?因为这个简单的CSS语句有效! :) - Pak
1
三年后,在移动版Safari上,这仍然是一个解决方案。在Chrome和Firefox上一切正常,但是在Safari上,我们不得不将此添加到仅有几个未正确触发的父容器中,更喜欢一种隔离的方法。 - Aaron Belchamber
我在使用React和material-ui时遇到了一个bug,添加一个虚拟的onClick={function(){}}使得mouseleave事件能够正确地在我的元素上被调用。这很疯狂,但它起作用了。 - Owen Allen

7

你试过这个吗?这是因为iOS有时不会触发点击事件,只能识别触摸事件。

$(document).on('touchstart click', [Selector], [ Event ]

11
谢谢。似乎添加touchstart事件可以解决问题。然而,这可能不是最佳解决方案,因为即使用户只是试图滚动并将手指放在链接上,动作也会被触发。有没有比使用touchstart更好的方法? - watt
对我来说,这会触发两次,在我有一个切换的地方,我的弹出窗口会显示一小段时间然后再隐藏。 - harri

6

只需声明这些空事件监听器即可。试试看:)

这将使其在所有浏览器上都有效:

container.addEventListener('touchstart', () => {});
container.addEventListener('touchend', () => {});
container.addEventListener('touchcancel', () => {});
container.addEventListener('touchmove', () => {});

3
有趣。您能详细说明为什么这起作用吗?因为它表现良好! - daamsie

4

移动设备有一个额外的事件。尝试添加tap事件监听器以及click事件。它们可以通过以下方式同时附加:

$(document).on('click tap', [selector], [handler])

谢谢,我猜你是指“轻触”。我尝试了大多数事件,但没有结果。 - watt
也许发布结构会有所帮助,这样可以看到DOM。也许事件在其他地方被捕获而不是通过冒泡传递。 - xanobius

2

对我来说,这个行为是随机的。一切都正常工作,但在一些更改后,某些按钮点击事件的随机问题出现了。

问题出现在某些移动设备上的按钮悬停上(至少对我而言,在Safari上的iOS iPad上),我通过在所有悬停中添加@media hover和指针附加来修复它:

@media (hover: hover) and (pointer: fine) {
    .topnav a:hover {
        background-color: lightcoral;
    }
}

这篇文章帮助我理解了这个问题(即使我这里没有使用React)https://github.com/facebook/react/issues/7635#issuecomment-365089006


2

刚刚花了一个小时调试另一个疯狂的场景,Safari吞掉了所有的点击,而以上的提示都没有帮助,问题似乎突然出现了。

简而言之:如果基础CSS在悬停时导致回流,冒泡不会到达发生回流的元素。

考虑以下标记:

container
  div 
    span

    container.addEventListener('click', MouseClick, false)

span {opacity: 0;} 

div:hover {
    span {opacity: 1;}
 }

因此,在移动版Safari中,由于第一次点击等同于悬停事件,并且这会触发(远小于div并且在点击目标坐标之外)上的CSS回流,所以
元素不会接收到事件。同时,同一
内发生的其他css悬停事件不会导致丢失点击。

当我将其缩小到CSS时,我感到震惊。幸运的是,它昨天被添加到代码库中,并且很容易跟踪,但是哇,为Safari开发真的很糟糕。


1
这是一个疯狂的问题,确实LinusR的答案quirksmode上的描述是准确的。我的普通点击事件监听器在iOS Safari中无法工作,因为这个原因:
window.addEventListener('click', function(event) {
    alert("Where's my click?!");
});

我现在已经用一个<div onclick="void(0);"></div>包装了我的应用程序,这样可以正常工作。我还添加了一些额外的东西来解决一些问题:

<div onclick="void(0);" style="height: 100%; -webkit-tap-highlight-color: transparent;">
  <div style="height: 100%; -webkit-tap-highlight-color: initial;">
    <my-app></my-app>
  </div>
</div>

我需要 height: 100%; 来使整个页面都可以点击,因为我需要这样做。如果你不使用 height: 100%; ,那么点击事件仍然只会在 div 的高度内触发。 -webkit-tap-highlight-color: transparent; 是为了防止 onclick 闪烁叠加样式,因为 iOS 默认情况下会对可点击元素执行此操作。之后的 div 恢复了该 CSS 属性的初始值,以便其他可点击元素在这方面具有正常行为。有关更多信息,请参见 this answer

0
在我的情况下,按钮带有像边框:3px这样的大小变化属性的:hover/:focus。
微小的尺寸变化足以重新排列位置并使点击无效。
这种情况发生在移动设备上,只是因为空间有限。

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