为我的 Web 应用程序创建自定义右键单击上下文菜单

我有一些网站,如google-docs和map-quest,当你右键单击时,它们有自定义的下拉菜单。不知何故,它们会覆盖浏览器的下拉菜单行为,我现在确切地确定它们是如何做到的。我发现了一个jQuery插件可以做到这一点,但我仍然对一些事情感到好奇:

  • 这是如何工作的?浏览器的下拉菜单实际上是否被覆盖,或者只是模拟效果?如果是这样,如何?
  • 插件抽象出什么?幕后发生了什么?
  • 这是达到这种效果的唯一途径吗?

custom context menu image

查看操作中的多个自定义上下文菜单


答案 1

我知道这个问题很老了,但只是想出了同样的问题并自己解决了,所以我正在回答,以防有人像我一样通过谷歌找到这个问题。我的解决方案基于@Andrew的解决方案,但之后基本上修改了所有内容。

编辑:看到最近这有多受欢迎,我决定也更新样式,使其看起来更像2014年,而不像Windows 95。我修复了@Quantico的错误,@Trengot发现,所以现在这是一个更可靠的答案。

编辑2:我用StackSnippets设置了它,因为它们是一个非常酷的新功能。我把好的jsfiddle留在这里供参考(点击第4个面板看看它们的工作原理)。

新的堆栈代码段:

// JAVASCRIPT (jQuery)

// Trigger action when the contexmenu is about to be shown
$(document).bind("contextmenu", function (event) {
    
    // Avoid the real one
    event.preventDefault();
    
    // Show contextmenu
    $(".custom-menu").finish().toggle(100).
    
    // In the right position (the mouse)
    css({
        top: event.pageY + "px",
        left: event.pageX + "px"
    });
});


// If the document is clicked somewhere
$(document).bind("mousedown", function (e) {
    
    // If the clicked element is not the menu
    if (!$(e.target).parents(".custom-menu").length > 0) {
        
        // Hide it
        $(".custom-menu").hide(100);
    }
});


// If the menu element is clicked
$(".custom-menu li").click(function(){
    
    // This is the triggered action name
    switch($(this).attr("data-action")) {
        
        // A case for each action. Your actions here
        case "first": alert("first"); break;
        case "second": alert("second"); break;
        case "third": alert("third"); break;
    }
  
    // Hide it AFTER the action was triggered
    $(".custom-menu").hide(100);
  });
/* CSS3 */

/* The whole thing */
.custom-menu {
    display: none;
    z-index: 1000;
    position: absolute;
    overflow: hidden;
    border: 1px solid #CCC;
    white-space: nowrap;
    font-family: sans-serif;
    background: #FFF;
    color: #333;
    border-radius: 5px;
    padding: 0;
}

/* Each of the items in the list */
.custom-menu li {
    padding: 8px 12px;
    cursor: pointer;
    list-style-type: none;
    transition: all .3s ease;
    user-select: none;
}

.custom-menu li:hover {
    background-color: #DEF;
}
<!-- HTML -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.js"></script>

<ul class='custom-menu'>
  <li data-action="first">First thing</li>
  <li data-action="second">Second thing</li>
  <li data-action="third">Third thing</li>
</ul>

<!-- Not needed, only for making it clickable on StackOverflow -->
Right click me

注意:您可能会看到一些小错误(远离光标的下拉列表等),请确保它在jsfiddle中工作,因为这比StackSnippets更类似于您的网页。


答案 2

正如Adrian所说,插件将以相同的方式工作。您将需要三个基本部分:

1:事件的事件处理程序:'contextmenu'

$(document).bind("contextmenu", function(event) {
    event.preventDefault();
    $("<div class='custom-menu'>Custom menu</div>")
        .appendTo("body")
        .css({top: event.pageY + "px", left: event.pageX + "px"});
});

在这里,您可以将事件处理程序绑定到要为其显示菜单的任何选择器。我选择了整个文档。

2:事件的事件处理程序(关闭自定义菜单):'click'

$(document).bind("click", function(event) {
    $("div.custom-menu").hide();
});

3:CSS控制菜单的位置:

.custom-menu {
    z-index:1000;
    position: absolute;
    background-color:#C0C0C0;
    border: 1px solid black;
    padding: 2px;
}

CSS 的重要一点是包含 和z-indexposition: absolute

将所有这些包装在光滑的jQuery插件中并不难。

您可以在此处看到一个简单的演示:http://jsfiddle.net/andrewwhitaker/fELma/