禁用Android上长按时的上下文菜单

68
我希望能够在我的Web应用程序中禁用长按(触摸和按住)图像后出现的上下文菜单。我看到了一些帖子提供了不同的想法,但是它们似乎都对我无效。是否有一种通过HTML / CSS / Javascript在Android上完成此操作的方法?
12个回答

182

上下文菜单有其自己的事件。您只需要捕获它并停止其传播。

window.oncontextmenu = function(event) {
     event.preventDefault();
     event.stopPropagation();
     return false;
};

可以了!但现在我想只在锚元素上阻止上下文菜单。我的过滤器已经起作用了(当[a]时返回false,否则返回true),但是返回true不会显示对话框。那么,你如何告诉浏览器它应该显示呢? - REJH
正在为Cordova Windows开发Win10/UWP/MS Edge WebView :) - Neptune Systems
你如何在React类组件中使用这个? - KaMZaTa
1
在我的Firefox Android上无法工作。 - Flafy
警告!此方法会对手机产生副作用,即令人讨厌的振动。每次长按都会使设备振动,就像显示上下文菜单一样。请投票支持此评论,以便其他人也能得到警告。 - HolyResistance
显示剩余2条评论

41

如果我没记错的话,这应该可以在1.6或更新版本上运行。我不认为在1.5或更早版本上有任何解决方法。

<!DOCTYPE html>
<html>
<head>
  <script>
    function absorbEvent_(event) {
      var e = event || window.event;
      e.preventDefault && e.preventDefault();
      e.stopPropagation && e.stopPropagation();
      e.cancelBubble = true;
      e.returnValue = false;
      return false;
    }

    function preventLongPressMenu(node) {
      node.ontouchstart = absorbEvent_;
      node.ontouchmove = absorbEvent_;
      node.ontouchend = absorbEvent_;
      node.ontouchcancel = absorbEvent_;
    }

    function init() {
      preventLongPressMenu(document.getElementById('theimage'));
    }
  </script>
</head>
<body onload="init()">
  <img id="theimage" src="http://www.google.com/logos/arthurboyd2010-hp.jpg" width="400">
</body>
</html>

5
自8月8日后没有看到原帖作者的任何消息,因此我决定使用SDK进行测试。我测试了1.5、1.6和2.2版本,发现在这些版本上都可以正常工作,因此我很高兴地决定立即授予奖励,而不必等待原帖作者确认。此外,也为这个好答案点赞。 - Andy E
1
@Andy:听起来是个好主意。我已经接受了Roman的答案,并将尝试进行更广泛的测试。如果似乎是设备故障,那就这样吧。如果不是,我会发布另一个更具体的问题。再次感谢对新来者在stackoverflow上的热烈欢迎! - Roy Sharon
10
该解决方案禁用了所有触摸事件。这可能会有所限制! - bbsimonbb
8
这真的是正确的答案吗?似乎 img.addEventListener('contextmenu', function(e) { e.preventDefault(); return false; }, false); 应该可以工作,不是吗?上述解决方案将阻止所有输入。 - gman
5
你经常会看到这种情况,但如果可以的话,你真的想避免干涉事件的传播。某个事件对于“你”的组件以及页面上的其他组件都可能具有重要意义。例如,在下拉菜单外单击可能是将下拉菜单收起来的信号,同时也可能是与该单击直接相对应的任何操作。找到一种方法,不要完全破坏页面上的事件处理。 - bbsimonbb
显示剩余6条评论

9

这可以通过 使用CSS 完成:

img {
  pointer-events: none;
}

2
这不仅禁用了长按,还禁用了普通的点击,因此并非总是一个选项。 - gvlasov

9

对于我来说,吸收所有事件并不是一个选项,因为我想禁用长按下载功能,同时仍允许用户缩放和平移图像。我能够仅通过CSS和HTML解决这个问题,方法是在图片上层叠一个“盾牌”div:

<div class="img-container">
  <div class="shield"></div>
  <img src="img-file.jpg">
</div>

<style>
.img-container { position: relative; }

img { max-width: 100%; }

.shield {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1;
}
</style>

希望这能帮助到某些人!

您可能需要在父容器中添加position:relative,以防止父容器占用所有空间。如果父容器是一个带有ontouchstart或其他交互事件处理程序的td,这将特别棘手,因为您不会在视觉上看到td占用了所有区域。 - Daniel F
不错的建议,Daniel。我添加了 position: relative 的 CSS 规则。 - Brian FitzGerald

7

它将禁用复制功能,但不会禁止选择。

document.oncontextmenu = function() {return false;};

适用于webView。


5
我使用了Nurik提供的完整示例,但是我的页面上的元素(一个输入图片)也被禁用了点击。
我将原来的代码行替换为以下内容:
node.ontouchstart = absorbEvent_;

我的零钱:
node.ontouchstart = node.onclick;

通过这种方法,我禁用了长按弹出保存图片菜单,但保留了点击事件。
我正在使用 Android 2.2 操作系统下的 Dolphin HD 浏览器在一台 7 英寸平板电脑上进行测试,效果很好!

4
请使用以下CSS代码适配移动设备:
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/copy in UIWebView */

1
这对于所请求的浏览器Chrome不起作用。 - bbsimonbb

4
pointer-events: none; // for Android

-webkit-touch-callout: none; // for iOS

-webkit-user-select: none; 

-khtml-user-select: none; 

-moz-user-select: none; 

-ms-user-select: none; 

user-select: none;

2
请添加一些解释说明答案。 - jjj
1
pointer-events: none; 本质上是 CSS 中元素的 return false,因此在这种情况下它会使我的按钮无法工作。 - Vael Victus

2
我曾经遇到过类似的问题。我尝试了这个线程和另一个线程中的一些解决方案,针对Safari上相同的问题(Preventing default context menu on longpress / longclick in mobile Safari (iPad / iPhone))。不好的一点是我无法使用onTouchStart、onTouchEnd等...
只需阻止onContextMenu事件即可。以下是React 16.5.2的片段。仅在Chrome中测试。

    <img {...props} onContextMenu={event => event.preventDefault()}
    onTouchStart={touchStart}
    onTouchEnd={touchEnd} />

希望这能帮到一些人。干杯!

0
<a id="moo" href=''> </a>

<script type="text/javascript">
    var moo = document.getElementById('moo');

    function handler(event) {
        event = event || context_menu.event;

        if (event.stopPropagation)
            event.stopPropagation();

        event.cancelBubble = true;
        return false;
    }

    moo.innerHTML = 'right-click here';

    moo.onclick = handler;
    moo.onmousedown = handler;
    moo.onmouseup = handler;
</script>

捕获onContextMenu事件,并在事件处理程序中返回false。

您还可以捕获单击事件,并使用event.button检查哪个鼠标按钮触发了事件,在某些浏览器中是这样的。


1
抱歉,这两种方法在Android上都不起作用。oncontextmenu事件从未被触发,而当用户长按元素时,click事件尚未被触发。 - Roy Sharon

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