如何在网页上添加自定义右键菜单?


291

我想向我的Web应用程序添加一个自定义的右键单击菜单。无需使用任何预构建的库就可以做到吗?如果是这样,如何显示不使用第三方JavaScript库的简单自定义右键单击菜单?

我的目标是像Google文档那样。它使用户可以右键单击并向用户显示他们自己的菜单。

注意: 我想学习如何制作自己的东西,而不是使用大多数人以来已经制作的东西,那些第三方库充斥着功能,而我只想要我需要的功能,因此我希望它完全是手工制作的我。



2
绝对不是重复的。由于该问题需要答案,而没有第三方库,而另一个可能使用Jquery (我想在用户脚本中编写上下文Google的驱动器,如上下文菜单)
user2284570 2015年

就在今天,我发现了两个关于这个的更好的例子:DEMO 1 // DEMO 2(这个演示需要jquery UI)我希望对任何人都有帮助,bb。
Drako

2
只想指出,HTML5上下文菜单仅在某些版本的Firefox中受支持,据我所知,没有任何其他支持。从61版开始的Chrome不支持它。
丹·威利特

2
对于使用React的人- 本机菜单会复制所有现有功能(复制,在新标签页中打开,在Google上进行搜索等),同时看起来是本机(根据浏览器使用不同的样式)。演示
samdd '18

Answers:


247

回答您的问题-使用contextmenu事件,如下所示:

if (document.addEventListener) {
  document.addEventListener('contextmenu', function(e) {
    alert("You've tried to open context menu"); //here you draw your own menu
    e.preventDefault();
  }, false);
} else {
  document.attachEvent('oncontextmenu', function() {
    alert("You've tried to open context menu");
    window.event.returnValue = false;
  });
}
<body>
  Lorem ipsum...
</body>

但是您应该问自己,您是否真的要覆盖默认的右键单击行为-这取决于您正在开发的应用程序。


JSFIDDLE


12
在Opera 11.01,Firefox 3.6.13,Chrome 9,Safari 5(全部通过addEventListener 4)和IE 8(attachEvent)上进行了测试。
Radek Benkel '02

54
您刚刚解释了如何禁用右键菜单。如何创建我们自己的菜单?
Shashwat 2012年

13
@Shashwat您知道用户单击过的地方,并且您没有原始菜单。在该位置创建一个容器,然后在此处显示菜单。
Radek Benkel 2012年


4
@shanehoban当您研究代码时,将看到此行e.preventDefault();。这就是为什么不显示常规菜单的原因。您可以做的是创建一些条件逻辑,以检查是否在右键单击时按下了键,然后又未调用e.preventDefault()-您将获得常规的浏览器菜单。
Radek Benkel

54

对我来说非常有用。为了像我这样的人,期待菜单的绘制,我将用于制作右键单击菜单的代码放在这里:

$(document).ready(function() {


  if ($("#test").addEventListener) {
    $("#test").addEventListener('contextmenu', function(e) {
      alert("You've tried to open context menu"); //here you draw your own menu
      e.preventDefault();
    }, false);
  } else {

    //document.getElementById("test").attachEvent('oncontextmenu', function() {
    //$(".test").bind('contextmenu', function() {
    $('body').on('contextmenu', 'a.test', function() {


      //alert("contextmenu"+event);
      document.getElementById("rmenu").className = "show";
      document.getElementById("rmenu").style.top = mouseY(event) + 'px';
      document.getElementById("rmenu").style.left = mouseX(event) + 'px';

      window.event.returnValue = false;


    });
  }

});

// this is from another SO post...  
$(document).bind("click", function(event) {
  document.getElementById("rmenu").className = "hide";
});



function mouseX(evt) {
  if (evt.pageX) {
    return evt.pageX;
  } else if (evt.clientX) {
    return evt.clientX + (document.documentElement.scrollLeft ?
      document.documentElement.scrollLeft :
      document.body.scrollLeft);
  } else {
    return null;
  }
}

function mouseY(evt) {
  if (evt.pageY) {
    return evt.pageY;
  } else if (evt.clientY) {
    return evt.clientY + (document.documentElement.scrollTop ?
      document.documentElement.scrollTop :
      document.body.scrollTop);
  } else {
    return null;
  }
}
.show {
  z-index: 1000;
  position: absolute;
  background-color: #C0C0C0;
  border: 1px solid blue;
  padding: 2px;
  display: block;
  margin: 0;
  list-style-type: none;
  list-style: none;
}

.hide {
  display: none;
}

.show li {
  list-style: none;
}

.show a {
  border: 0 !important;
  text-decoration: none;
}

.show a:hover {
  text-decoration: underline !important;
}
<!-- jQuery should be at least version 1.7 -->
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="contextmenu.js"></script>
<link rel="stylesheet" href="contextmenu.css" />


<div id="test1">
  <a href="www.google.com" class="test">Google</a>
  <a href="www.google.com" class="test">Link 2</a>
  <a href="www.google.com" class="test">Link 3</a>
  <a href="www.google.com" class="test">Link 4</a>
</div>

<!-- initially hidden right-click menu -->
<div class="hide" id="rmenu">
  <ul>
    <li>
      <a href="http://www.google.com">Google</a>
    </li>

    <li>
      <a href="http://localhost:8080/login">Localhost</a>
    </li>

    <li>
      <a href="C:\">C</a>
    </li>
  </ul>
</div>


7
带有@Schism后缀mouseY(event)mouseX(event)px使其按预期工作:http : //jsfiddle.net/a6w7n64o/
zanetu 2015年

3
您正在通过ID引用元素,test但没有通过ID 引用元素test。只有类别为的元素test
马歇尔公爵שלום2015年

1
@Adelphia-任何非本地的,非您自己创建的东西都是第三方。jQuery真的不是多余的东西stuff肿了。不至于会降低任何速度。这非常有用,jQuery此答案中使用的相同内容可以轻松转换为标准JavaScript命令。它可能与原始问题中的请求不是100%内联,但绝对是95%与它内联。
马歇尔公爵שלום2015年

6
在firefox 39中,默认上下文菜单仍显示在自定义菜单的顶部。同样,自定义菜单在显示后立即关闭。
马特

1
@Matt我在Firefox 58中遇到了同样的问题。这篇文章介绍了一种适用于我的解决方案:stackoverflow.com/a/40545465/2922675您禁用文档的事件传播并在window对象上注册您的上下文菜单处理程序。这是经过调整的小提琴:jsfiddle.net/jjgkLe3g/1
Nils-o-mat

27

一些不错的CSS和一些没有外部库的非标准html标记的组合可以提供不错的结果(JSFiddle)

的HTML

<menu id="ctxMenu">
    <menu title="File">
        <menu title="Save"></menu>
        <menu title="Save As"></menu>
        <menu title="Open"></menu>
    </menu>
    <menu title="Edit">
        <menu title="Cut"></menu>
        <menu title="Copy"></menu>
        <menu title="Paste"></menu>
    </menu>
</menu>

注意:菜单标签不存在,我正在整理(您可以使用任何东西)

的CSS

#ctxMenu{
    display:none;
    z-index:100;
}
menu {
    position:absolute;
    display:block;
    left:0px;
    top:0px;
    height:20px;
    width:20px;
    padding:0;
    margin:0;
    border:1px solid;
    background-color:white;
    font-weight:normal;
    white-space:nowrap;
}
menu:hover{
    background-color:#eef;
    font-weight:bold;
}
menu:hover > menu{
    display:block;
}
menu > menu{
    display:none;
    position:relative;
    top:-20px;
    left:100%;
    width:55px;
}
menu[title]:before{
    content:attr(title);
}
menu:not([title]):before{
    content:"\2630";
}

JavaScript的只是在这个例子中,我个人将其删除Windows上的持久菜单

var notepad = document.getElementById("notepad");
notepad.addEventListener("contextmenu",function(event){
    event.preventDefault();
    var ctxMenu = document.getElementById("ctxMenu");
    ctxMenu.style.display = "block";
    ctxMenu.style.left = (event.pageX - 10)+"px";
    ctxMenu.style.top = (event.pageY - 10)+"px";
},false);
notepad.addEventListener("click",function(event){
    var ctxMenu = document.getElementById("ctxMenu");
    ctxMenu.style.display = "";
    ctxMenu.style.left = "";
    ctxMenu.style.top = "";
},false);

另请注意,您可以将修改menu > menu{left:100%;}menu > menu{right:100%;},以从右向左展开菜单。您需要在某些地方添加边距或其他内容


20

根据此处和其他流程的答案,我制作了一个看起来像Google Chrome浏览器的版本,并带有css3过渡。 JS Fiddle

让我们开始吧,因为我们在此页面上具有上面的js,所以我们可以担心CSS和布局。我们将使用的布局是一个<a>元素,其中包含一个<img>元素或一个超棒的字体图标(<i class="fa fa-flag"></i>)和a <span>以显示键盘快捷键。所以这是结构:

<a href="#" onclick="doSomething()">
  <img src="path/to/image.gif" />
  This is a menu option
  <span>Ctrl + K</span>
</a>

我们将它们放在一个div中,并在右键单击上显示该div。让我们像在Google Chrome中那样对它们进行样式设置,对吗?

#menu a {
  display: block;
  color: #555;
  text-decoration: no[...]

现在,我们将从接受的答案中添加代码,并获取光标的X和Y值。为此,我们将使用e.clientXe.clientY。我们正在使用客户端,因此菜单div必须固定。

var i = document.getElementById("menu").style;
if (document.addEventListener) {
  document.addEventListener('contextmenu', function(e) {
    var posX = e.clientX;
    var posY = e.client[...]

就是这样!只需添加css转换即可淡入和淡出,然后完成!


这节省了我很大的头痛!如果OP希望在整个网页上而不是仅在div上使用一种简单的方法,那么应该接受以下答案:)
伍迪(Woody)

12

您可以尝试通过将以下内容添加到body标签来简单地阻止上下文菜单:

<body oncontextmenu="return false;">

这将阻止所有对上下文菜单的访问(不仅是鼠标右键,还有键盘)。

PS,您可以将此添加到您要在其上禁用上下文菜单的任何标签

例如:

<div class="mydiv" oncontextmenu="return false;">

仅在该特定div中禁用上下文菜单


10
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<head>

<title>Context menu - LabLogic.net</title>

</head>
<body>

<script language="javascript" type="text/javascript">

document.oncontextmenu=RightMouseDown;
document.onmousedown = mouseDown; 



function mouseDown(e) {
    if (e.which==3) {//righClick
        alert("Right-click menu goes here");
    }
}


function RightMouseDown() { return false; }

</script>

</body>
</html>

在Opera 11.6,firefox 9.01,Internet Explorer 9和chrome 17中经过测试并可以工作。您可以在javascript右键菜单上查看有效的示例


它可以工作,但是页面上的演示菜单确实很小而且很局促。很好的例子。
David Millar 2013年

2
如果您使用的是三键鼠标,则可以使用它。按住Ctrl键单击并保持干燥。@Singles有一个更好的建议,即使它确实有些想像。
AJFarkas 2014年

7

我知道已经回答了这个问题,但是我花了一些时间努力解决第二个问题,以使本机上下文菜单消失显示在用户单击的位置。
的HTML

<body>
    <div id="test1">
        <a href="www.google.com" class="test">Google</a>
        <a href="www.google.com" class="test">Link 2</a>
        <a href="www.google.com" class="test">Link 3</a>
        <a href="www.google.com" class="test">Link 4</a>
    </div>

    <!-- initially hidden right-click menu -->
    <div class="hide" id="rmenu">
        <ul>
            <li class="White">White</li>
            <li>Green</li>
            <li>Yellow</li>
            <li>Orange</li>
            <li>Red</li>
            <li>Blue</li>
        </ul>
    </div>
</body>

的CSS

.hide {
  display: none;
}

#rmenu {
  border: 1px solid black;
  background-color: white;
}

#rmenu ul {
  padding: 0;
  list-style: none;
}
#rmenu li
{
  list-style: none;
  padding-left: 5px;
  padding-right: 5px;
}

的JavaScript

if (document.getElementById('test1').addEventListener) {
    document.getElementById('test1').addEventListener('contextmenu', function(e) {
            $("#rmenu").toggleClass("hide");
            $("#rmenu").css(
              {
                position: "absolute",
                top: e.pageY,
                left: e.pageX
              }
            );
            e.preventDefault();
     }, false);
}

// this is from another SO post...  
$(document).bind("click", function(event) {
  document.getElementById("rmenu").className = "hide";
});

CodePen示例


6

尝试这个

$(function() {
var doubleClicked = false;
$(document).on("contextmenu", function (e) {
if(doubleClicked == false) {
e.preventDefault(); // To prevent the default context menu.
var windowHeight = $(window).height()/2;
var windowWidth = $(window).width()/2;
if(e.clientY > windowHeight && e.clientX <= windowWidth) {
  $("#contextMenuContainer").css("left", e.clientX);
  $("#contextMenuContainer").css("bottom", $(window).height()-e.clientY);
  $("#contextMenuContainer").css("right", "auto");
  $("#contextMenuContainer").css("top", "auto");
} else if(e.clientY > windowHeight && e.clientX > windowWidth) {
  $("#contextMenuContainer").css("right", $(window).width()-e.clientX);
  $("#contextMenuContainer").css("bottom", $(window).height()-e.clientY);
  $("#contextMenuContainer").css("left", "auto");
  $("#contextMenuContainer").css("top", "auto");
} else if(e.clientY <= windowHeight && e.clientX <= windowWidth) {
  $("#contextMenuContainer").css("left", e.clientX);
  $("#contextMenuContainer").css("top", e.clientY);
  $("#contextMenuContainer").css("right", "auto");
  $("#contextMenuContainer").css("bottom", "auto");
} else {
  $("#contextMenuContainer").css("right", $(window).width()-e.clientX);
  $("#contextMenuContainer").css("top", e.clientY);
  $("#contextMenuContainer").css("left", "auto");
  $("#contextMenuContainer").css("bottom", "auto");
}
 $("#contextMenuContainer").fadeIn(500, FocusContextOut());
  doubleClicked = true;
} else {
  e.preventDefault();
  doubleClicked = false;
  $("#contextMenuContainer").fadeOut(500);
}
});
function FocusContextOut() {
 $(document).on("click", function () {
   doubleClicked = false; 
   $("#contextMenuContainer").fadeOut(500);
   $(document).off("click");           
 });
}
});

http://jsfiddle.net/AkshayBandivadekar/zakn7​​Lwb/14/


代码很棒,但是请提供一些有关OP实际问题以及如何解决的描述。
罗里·麦克罗森

我喜欢这种解决方案,但是在firefox 39中,菜单在出现后立即自行关闭。
马特

如果强制页面进行滚动(例如,添加了一堆<br>标签)并且该页面位于页面底部,则该解决方案实际上不起作用。
DanielM

您应该使用clientX和clientY而不是pageX和pageY来工作。检查出这个伟大的答案:stackoverflow.com/questions/9262741/...
DanielM

是的,DanielM滚动时在右键菜单上存在问题,因此通过使用clientX和clientY而不是pageX和pageY可以解决此问题,我对代码进行了更改。感谢您的帮助...
AkshayBandivadekar

5

纯JS和CSS解决方案,可实现真正的动态右键单击上下文菜单,尽管基于元素ID,链接等的预定义命名约定 。jsfiddle 和您可以复制的代码粘贴到单个静态html页面中:

<html>

<head>
  <style>
    .cls-context-menu-link {
      display: block;
      padding: 20px;
      background: #ECECEC;
    }
    
    .cls-context-menu {
      position: absolute;
      display: none;
    }
    
    .cls-context-menu ul,
    #context-menu li {
      list-style: none;
      margin: 0;
      padding: 0;
      background: white;
    }
    
    .cls-context-menu {
      border: solid 1px #CCC;
    }
    
    .cls-context-menu li {
      border-bottom: solid 1px #CCC;
    }
    
    .cls-context-menu li:last-child {
      border: none;
    }
    
    .cls-context-menu li a {
      display: block;
      padding: 5px 10px;
      text-decoration: none;
      color: blue;
    }
    
    .cls-context-menu li a:hover {
      background: blue;
      color: #FFF;
    }
  </style>
</head>

<body>

  <!-- those are the links which should present the dynamic context menu -->
  <a id="link-1" href="#" class="cls-context-menu-link">right click link-01</a>
  <a id="link-2" href="#" class="cls-context-menu-link">right click link-02</a>

  <!-- this is the context menu -->
  <!-- note the string to=0 where the 0 is the digit to be replaced -->
  <div id="div-context-menu" class="cls-context-menu">
    <ul>
      <li><a href="#to=0">link-to=0 -item-1 </a></li>
      <li><a href="#to=0">link-to=0 -item-2 </a></li>
      <li><a href="#to=0">link-to=0 -item-3 </a></li>
    </ul>
  </div>

  <script>
    var rgtClickContextMenu = document.getElementById('div-context-menu');

    /** close the right click context menu on click anywhere else in the page*/
    document.onclick = function(e) {
      rgtClickContextMenu.style.display = 'none';
    }

    /**
     present the right click context menu ONLY for the elements having the right class
     by replacing the 0 or any digit after the "to-" string with the element id , which
     triggered the event
    */
    document.oncontextmenu = function(e) {
      //alert(e.target.id)
      var elmnt = e.target
      if (elmnt.className.startsWith("cls-context-menu")) {
        e.preventDefault();
        var eid = elmnt.id.replace(/link-/, "")
        rgtClickContextMenu.style.left = e.pageX + 'px'
        rgtClickContextMenu.style.top = e.pageY + 'px'
        rgtClickContextMenu.style.display = 'block'
        var toRepl = "to=" + eid.toString()
        rgtClickContextMenu.innerHTML = rgtClickContextMenu.innerHTML.replace(/to=\d+/g, toRepl)
        //alert(rgtClickContextMenu.innerHTML.toString())
      }
    }
  </script>
</body>

</html>


这是我所期望的更多答案,实际上是修改右键单击菜单的示例
Jesse Reza Khorasanee

是的,类似的示例可能是:codepen.io/yordangeorgiev/pen/GzWJzd和最终产品:qto.fi/qto/view/concepts_doc(只需单击登录...)
Yordan Georgiev

3

这是一个很好的教程,说明如何使用完整的工作代码示例(没有JQuery和其他库)构建自定义上下文菜单

您还可以在GitHub上找到他们的演示代码

他们给出了详细的分步说明,您可以按照这些步骤逐步构建自己的右键单击上下文菜单(包括html,css和javascript代码),并在最后通过提供完整的示例代码对其进行总结。

您可以轻松地按照自己的需要进行调整。并且不需要JQuery或其他库。

他们的示例菜单代码如下所示:

<nav id="context-menu" class="context-menu">
    <ul class="context-menu__items">
      <li class="context-menu__item">
        <a href="#" class="context-menu__link" data-action="View"><i class="fa fa-eye"></i> View Task</a>
      </li>
      <li class="context-menu__item">
        <a href="#" class="context-menu__link" data-action="Edit"><i class="fa fa-edit"></i> Edit Task</a>
      </li>
      <li class="context-menu__item">
        <a href="#" class="context-menu__link" data-action="Delete"><i class="fa fa-times"></i> Delete Task</a>
      </li>
    </ul>
  </nav>

可以在codepen上找到一个工作示例(任务列表)


简短的摘要可以帮助审阅者(如我)判断您答案的正确性,并可以使一些读者免于关注该链接。只需一两句话就可以了,不需要太多的工作。
Ingo Karkat

@IngoKarkat感谢您的建议。我添加了一些解释。希望对您有所帮助。这对我帮助很大。
ForceOfWill

2

您可以使用此代码来实现。请访问此处以获取有关自动边缘检测的完整教程http://www.voidtricks.com/custom-right-click-context-menu/

$(document).ready(function () {
 $("html").on("contextmenu",function(e){
        //prevent default context menu for right click
        e.preventDefault();

        var menu = $(".menu"); 

        //hide menu if already shown
        menu.hide(); 

        //get x and y values of the click event
        var pageX = e.pageX;
        var pageY = e.pageY;

        //position menu div near mouse cliked area
        menu.css({top: pageY , left: pageX});

        var mwidth = menu.width();
        var mheight = menu.height();
        var screenWidth = $(window).width();
        var screenHeight = $(window).height();

        //if window is scrolled
        var scrTop = $(window).scrollTop();

        //if the menu is close to right edge of the window
        if(pageX+mwidth > screenWidth){
        menu.css({left:pageX-mwidth});
        }

        //if the menu is close to bottom edge of the window
        if(pageY+mheight > screenHeight+scrTop){
        menu.css({top:pageY-mheight});
        }

        //finally show the menu
        menu.show();
 }); 

 $("html").on("click", function(){
 $(".menu").hide();
 });
 });

`


1
<script language="javascript" type="text/javascript">
  document.oncontextmenu = RightMouseDown; 
  document.onmousedown = mouseDown; 

  function mouseDown(e) {
    if (e.which==3) {//righClick
      alert("Right-click menu goes here");
    } 
  }

  function RightMouseDown() { 
    return false; 
  }
</script>
</body> 
</html>

2
您知道有一个oncontextmenu事件被触发(通常是右键单击)
megawac

1

一种简单的方法是使用onContextMenu返回JavaScript函数:

<input type="button" value="Example" onContextMenu="return RightClickFunction();">

<script>
 function RightClickFunction() {
  // Enter your code here;
  return false;
 }
</script>

通过输入,return false;您将取消上下文菜单。

如果仍然要显示上下文菜单,则可以删除该return false;行。


1

经过测试并在Opera 12.17,firefox 30,Internet Explorer 9和chrome 26.0.1410.64中工作

document.oncontextmenu =function( evt ){
        alert("OK?");
        return false;
        }

1
当上下文菜单出现时,该突出显示按钮不会显示警报吗?我看不出它将如何对其进行自定义。
Stephen Ostermiller 2014年

1
<script>
function fun(){
document.getElementById('menu').style.display="block";
}

</script>
<div id="menu" style="display: none"> menu items</div>

<body oncontextmenu="fun();return false;">

我在这里做什么

  1. 创建您自己的自定义div菜单,并设置位置:“绝对”和“显示:无”,以防万一。
  2. 添加到要单击oncontextmenu事件的页面或元素。
  3. 通过返回false取消默认的浏览器操作。
  4. 用户js调用您自己的操作。


0

您应该记住是否要使用仅Firefox的解决方案,如果要将其添加到整个文档中,则应添加contextmenu="mymenu"<html>标记中,而不要添加到body标记中。
您应该注意这一点。


0
<html>
<head>
<style>
.rightclick {
    /* YOUR CONTEXTMENU'S CSS */
    visibility: hidden;
    background-color: white;
    border: 1px solid grey;
    width: 200px;
    height: 300px;
}
</style>
</head>
<body>
  <div class="rightclick" id="ya">
    <p onclick="alert('choc-a-late')">I like chocolate</p><br><p onclick="awe-so-me">I AM AWESOME</p>
  </div>
  <p>Right click to get sweet results!</p>
</body>
<script>
    document.onclick = noClick;
    document.oncontextmenu = rightClick;
    function rightClick(e) {
        e = e || window.event;
        e.preventDefault();
        document.getElementById("ya").style.visibility = "visible";
        console.log("Context Menu v1.3.0 by IamGuest opened.");
   }
function noClick() {
    document.getElementById("ya").style.visibility = "hidden";
    console.log("Context Menu v1.3.0 by IamGuest closed.");
}
</script>
<!-- Coded by IamGuest. Thank you for using this code! -->
</html>

您可以调整和修改此代码,以使外观更好,更有效。至于修改现有的上下文菜单,我不确定该怎么做。。。查看此小提琴以获得有组织的观点。另外,尝试单击我的上下文菜单中的项目。他们应该提醒您一些很棒的消息。如果它们不起作用,请尝试其他更复杂的方法。


0

我使用类似于以下jsfiddle的内容

function onright(el, cb) {
    //disable right click
    document.body.oncontextmenu = 'return false';
    el.addEventListener('contextmenu', function (e) { e.preventDefault(); return false });
    el.addEventListener('mousedown', function (e) {
        e = e || window.event;
        if (~~(e.button) === 2) {
            if (e.preventDefault) {
                e.preventDefault();
            } else {
                e.returnValue = false;
            }
            return false;
        }
    });

    // then bind Your cb
    el.addEventListener('mousedown', function (e) {
        e = e || window.event;
        ~~(e.button) === 2 && cb.call(el, e);
    });
}

如果您以较旧的IE浏览器为目标,则无论如何都应使用'attachEvent;来完成它。案件

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.