为我的 web 应用程序制作自定义右击上下文菜单

我有一些网站,如谷歌文档和地图寻找,有自定义下拉菜单,当你右击。不知怎么的,他们覆盖了浏览器的下拉菜单行为,我现在很清楚他们是怎么做到的。我发现一个 JQuery 插件可以做到这一点,但我仍然对一些事情感到好奇:

  • 这是怎么回事?浏览器的下拉菜单是真的被覆盖了,还是只是模拟了效果?如果是这样,怎么做?
  • 这个插件抽象出了什么? 幕后发生了什么?
  • 这是达到这种效果的唯一方法吗?

custom context menu image

查看几个实际使用的自定义上下文菜单

171281 次浏览

正在覆盖浏览器的上下文菜单。无法在任何主要浏览器中增加本机上下文菜单。

由于插件创建自己的菜单,唯一真正被抽象的部分是浏览器的上下文菜单事件。该插件根据您的配置创建一个 html 菜单,然后将该内容放置在您单击的位置。

是的,这是创建自定义上下文菜单的唯一方法。显然,不同的插件所做的事情略有不同,但它们都会覆盖浏览器的事件,并将自己的基于 html 的菜单放在正确的位置。

正如阿德里安所说,这些插件将以同样的方式工作。你需要三个基本部分:

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/

你可以看看这个教程: < a href = “ http://www.youtube.com/watch? v = iDyeffKWCzhg”rel = “ nofollow”> http://www.youtube.com/watch?v=idyefkwczhg 首先确保上下文菜单是隐藏的,并且具有绝对位置 确保不会有多个上下文菜单和无用的创建上下文菜单。该页面的链接放在 YouTube 视频的描述中。

$(document).bind("contextmenu", function(event){
$("#contextmenu").css({"top": event.pageY +  "px", "left": event.pageX +  "px"}).show();
});
$(document).bind("click", function(){
$("#contextmenu").hide();
});

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

编辑 : 看到这个最近有多流行,我决定也更新样式,使它看起来更像2014,而不是像 Windows 95。我修正了 Quantico 和 Trengot 发现的漏洞,现在这是一个更可靠的答案。

编辑2 : 我使用 StackSnipppet 设置它,因为它们是一个非常酷的新特性。我把 好的 jsfiddle留在这里作为参考(点击第四个面板查看它们的工作情况)。

新的堆栈片段:

// 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的工作,因为这是更类似于您的网页比 StackSnipppet 可能是。

<!DOCTYPE html>
<html>
<head>
<title>Right Click</title>


<link href="https://swisnl.github.io/jQuery-contextMenu/dist/jquery.contextMenu.css" rel="stylesheet" type="text/css" />


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://swisnl.github.io/jQuery-contextMenu/dist/jquery.contextMenu.js" type="text/javascript"></script>


<script src="https://swisnl.github.io/jQuery-contextMenu/dist/jquery.ui.position.min.js" type="text/javascript"></script>


</head>
<body>
<span class="context-menu-one" style="border:solid 1px black; padding:5px;">Right Click Me</span>
<script type="text/javascript">
        

$(function() {
$.contextMenu({
selector: '.context-menu-one',
callback: function(key, options) {
var m = "clicked: " + key;
window.console && console.log(m) || alert(m);
},
items: {
"edit": {name: "Edit", icon: "edit"},
"cut": {name: "Cut", icon: "cut"},
copy: {name: "Copy", icon: "copy"},
"paste": {name: "Paste", icon: "paste"},
"delete": {name: "Delete", icon: "delete"},
"sep1": "---------",
"quit": {name: "Quit", icon: function(){
return 'context-menu-icon context-menu-icon-quit';
}}
}
});


$('.context-menu-one').on('click', function(e){
console.log('clicked', this);
})
});
</script>
</body>
</html>

下面是一个在 javascript 中右击上下文菜单的例子: 右击上下文菜单

使用原始的 javasScript 代码实现上下文菜单功能。请您检查一下,希望对您有所帮助。

直播密码:

(function() {
  

"use strict";




/*********************************************** Context Menu Function Only ********************************/
function clickInsideElement( e, className ) {
var el = e.srcElement || e.target;
if ( el.classList.contains(className) ) {
return el;
} else {
while ( el = el.parentNode ) {
if ( el.classList && el.classList.contains(className) ) {
return el;
}
}
}
return false;
}


function getPosition(e) {
var posx = 0, posy = 0;
if (!e) var e = window.event;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
} else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
return {
x: posx,
y: posy
}
}


// Your Menu Class Name
var taskItemClassName = "thumb";
var contextMenuClassName = "context-menu",contextMenuItemClassName = "context-menu__item",contextMenuLinkClassName = "context-menu__link", contextMenuActive = "context-menu--active";
var taskItemInContext, clickCoords, clickCoordsX, clickCoordsY, menu = document.querySelector("#context-menu"), menuItems = menu.querySelectorAll(".context-menu__item");
var menuState = 0, menuWidth, menuHeight, menuPosition, menuPositionX, menuPositionY, windowWidth, windowHeight;


function initMenuFunction() {
contextListener();
clickListener();
keyupListener();
resizeListener();
}


/**
* Listens for contextmenu events.
*/
function contextListener() {
document.addEventListener( "contextmenu", function(e) {
taskItemInContext = clickInsideElement( e, taskItemClassName );


if ( taskItemInContext ) {
e.preventDefault();
toggleMenuOn();
positionMenu(e);
} else {
taskItemInContext = null;
toggleMenuOff();
}
});
}


/**
* Listens for click events.
*/
function clickListener() {
document.addEventListener( "click", function(e) {
var clickeElIsLink = clickInsideElement( e, contextMenuLinkClassName );


if ( clickeElIsLink ) {
e.preventDefault();
menuItemListener( clickeElIsLink );
} else {
var button = e.which || e.button;
if ( button === 1 ) {
toggleMenuOff();
}
}
});
}


/**
* Listens for keyup events.
*/
function keyupListener() {
window.onkeyup = function(e) {
if ( e.keyCode === 27 ) {
toggleMenuOff();
}
}
}


/**
* Window resize event listener
*/
function resizeListener() {
window.onresize = function(e) {
toggleMenuOff();
};
}


/**
* Turns the custom context menu on.
*/
function toggleMenuOn() {
if ( menuState !== 1 ) {
menuState = 1;
menu.classList.add( contextMenuActive );
}
}


/**
* Turns the custom context menu off.
*/
function toggleMenuOff() {
if ( menuState !== 0 ) {
menuState = 0;
menu.classList.remove( contextMenuActive );
}
}


function positionMenu(e) {
clickCoords = getPosition(e);
clickCoordsX = clickCoords.x;
clickCoordsY = clickCoords.y;
menuWidth = menu.offsetWidth + 4;
menuHeight = menu.offsetHeight + 4;


windowWidth = window.innerWidth;
windowHeight = window.innerHeight;


if ( (windowWidth - clickCoordsX) < menuWidth ) {
menu.style.left = (windowWidth - menuWidth)-0 + "px";
} else {
menu.style.left = clickCoordsX-0 + "px";
}


// menu.style.top = clickCoordsY + "px";


if ( Math.abs(windowHeight - clickCoordsY) < menuHeight ) {
menu.style.top = (windowHeight - menuHeight)-0 + "px";
} else {
menu.style.top = clickCoordsY-0 + "px";
}
}




function menuItemListener( link ) {
var menuSelectedPhotoId = taskItemInContext.getAttribute("data-id");
console.log('Your Selected Photo: '+menuSelectedPhotoId)
var moveToAlbumSelectedId = link.getAttribute("data-action");
if(moveToAlbumSelectedId == 'remove'){
console.log('You Clicked the remove button')
}else if(moveToAlbumSelectedId && moveToAlbumSelectedId.length > 7){
console.log('Clicked Album Name: '+moveToAlbumSelectedId);
}
toggleMenuOff();
}
initMenuFunction();


})();
/* For Body Padding and content */
body { padding-top: 70px; }
li a { text-decoration: none !important; }


/* Thumbnail only */
.thumb {
margin-bottom: 30px;
}
.thumb:hover a, .thumb:active a, .thumb:focus a {
border: 1px solid purple;
}


/************** For Context menu ***********/
/* context menu */
.context-menu {  display: none;  position: absolute;  z-index: 9999;  padding: 12px 0;  width: 200px;  background-color: #fff;  border: solid 1px #dfdfdf;  box-shadow: 1px 1px 2px #cfcfcf;  }
.context-menu--active {  display: block;  }


.context-menu__items { list-style: none;  margin: 0;  padding: 0;  }
.context-menu__item { display: block;  margin-bottom: 4px;  }
.context-menu__item:last-child {  margin-bottom: 0;  }
.context-menu__link {  display: block;  padding: 4px 12px;  color: #0066aa;  text-decoration: none;  }
.context-menu__link:hover {  color: #fff;  background-color: #0066aa;  }
.context-menu__items ul {  position: absolute;  white-space: nowrap;  z-index: 1;  left: -99999em;}
.context-menu__items > li:hover > ul {  left: auto;  padding-top: 5px  ;  min-width: 100%;  }
.context-menu__items > li li ul {  border-left:1px solid #fff;}
.context-menu__items > li li:hover > ul {  left: 100%;  top: -1px;  }
.context-menu__item ul { background-color: #ffffff; padding: 7px 11px;  list-style-type: none;  text-decoration: none; margin-left: 40px; }
.page-media .context-menu__items ul li { display: block; }
/************** For Context menu ***********/
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<body>






<!-- Page Content -->
<div class="container">


<div class="row">


<div class="col-lg-12">
<h1 class="page-header">Thumbnail Gallery <small>(Right click to see the context menu)</small></h1>
</div>


<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
<img class="img-responsive" src="http://placehold.it/400x300" alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
<img class="img-responsive" src="http://placehold.it/400x300" alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
<img class="img-responsive" src="http://placehold.it/400x300" alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
<img class="img-responsive" src="http://placehold.it/400x300" alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
<img class="img-responsive" src="http://placehold.it/400x300" alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
<img class="img-responsive" src="http://placehold.it/400x300" alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
<img class="img-responsive" src="http://placehold.it/400x300" alt="">
</a>
</div>
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
<img class="img-responsive" src="http://placehold.it/400x300" alt="">
</a>
</div>


</div>


<hr>




</div>
<!-- /.container -->




<!-- / The Context Menu -->
<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="Delete This Photo"><i class="fa fa-empire"></i> Delete This Photo</a>
</li>
<li class="context-menu__item">
<a href="#" class="context-menu__link" data-action="Photo Option 2"><i class="fa fa-envira"></i> Photo Option 2</a>
</li>
<li class="context-menu__item">
<a href="#" class="context-menu__link" data-action="Photo Option 3"><i class="fa fa-first-order"></i> Photo Option 3</a>
</li>
<li class="context-menu__item">
<a href="#" class="context-menu__link" data-action="Photo Option 4"><i class="fa fa-gitlab"></i> Photo Option 4</a>
</li>
<li class="context-menu__item">
<a href="#" class="context-menu__link" data-action="Photo Option 5"><i class="fa fa-ioxhost"></i> Photo Option 5</a>
</li>
<li class="context-menu__item">
<a href="#" class="context-menu__link"><i class="fa fa-arrow-right"></i> Add Photo to</a>
<ul>
<li><a href="#!" class="context-menu__link" data-action="album-one"><i class="fa fa-camera-retro"></i> Album One</a></li>
<li><a href="#!" class="context-menu__link" data-action="album-two"><i class="fa fa-camera-retro"></i> Album Two</a></li>
<li><a href="#!" class="context-menu__link" data-action="album-three"><i class="fa fa-camera-retro"></i> Album Three</a></li>
<li><a href="#!" class="context-menu__link" data-action="album-four"><i class="fa fa-camera-retro"></i> Album Four</a></li>
</ul>
</li>
</ul>
</nav>


<!-- End # Context Menu -->




</body>

我知道这也是相当古老的。我最近需要创建一个上下文菜单,我注入到其他网站,有不同的属性基于元素点击。

这是相当粗糙的,可能有更好的方法来实现这一点。 它使用 jQuery Context 菜单库 < a href = “ https://swisnl.github.io/jQuery-contextMenu//”rel = “ nofollow norefrer”> Location Here

我喜欢创造它,虽然你们可能有一些使用它。

这里是 小提琴。我希望它能帮助有希望的人在那里。

$(function() {
function createSomeMenu() {
var all_array = '{';
var x = event.clientX,
y = event.clientY,
elementMouseIsOver = document.elementFromPoint(x, y);
if (elementMouseIsOver.closest('a')) {
all_array += '"Link-Fold": {"name": "Link", "icon": "fa-external-link", "items": {"fold2-key1": {"name": "Open Site in New Tab"}, "fold2-key2": {"name": "Open Site in Split Tab"}, "fold2-key3": {"name": "Copy URL"}}},';
}
if (elementMouseIsOver.closest('img')) {
all_array += '"Image-Fold": {"name": "Image","icon": "fa-picture-o","items": {"fold1-key1": {"name":"Download Image"},"fold1-key2": {"name": "Copy Image Location"},"fold1-key3": {"name": "Go To Image"}}},';
}
all_array += '"copy": {"name": "Copy","icon": "copy"},"paste": {"name": "Paste","icon": "paste"},"edit": {"name": "Edit HTML","icon": "fa-code"}}';
return JSON.parse(all_array);
}


// setup context menu
$.contextMenu({
selector: 'body',
build: function($trigger, e) {
return {
callback: function(key, options) {
var m = "clicked: " + key;
console.log(m);
},
items: createSomeMenu()
};
}
});
});

我有一个使用 Bootstrap 的简单实现,如下所示。

<select class="custom-select" id="list" multiple></select>


<div class="dropdown-menu" id="menu-right-click" style=>
<h6 class="dropdown-header">Actions</h6>
<a class="dropdown-item" href="" onclick="option1();">Option 1</a>
<a class="dropdown-item" href="" onclick="option2();">Option 2</a>
</div>


<script>
$("#menu-right-click").hide();


$(document).on("contextmenu", "#list", function (e) {
$("#menu-right-click")
.css({
position: 'absolute',
left: e.pageX,
top: e.pageY,
display: 'block'
})
return false;
});


function option1() {
// something you want...
$("#menu-right-click").hide();
}


function option2() {
// something else
$("#menu-right-click").hide();
}
</script>

很简单

  1. 当右键单击文档中的任何位置时显示上下文菜单
  2. 单击上下文菜单时避免上下文菜单隐藏
  3. 按鼠标左键时关闭上下文菜单

注: 不要使用显示: 不要使用不透明来隐藏和显示

var menu= document.querySelector('.context_menu');
document.addEventListener("contextmenu", function(e) {
e.preventDefault();
menu.style.position = 'absolute';
menu.style.left = e.pageX + 'px';
menu.style.top = e.pageY + 'px';
menu.style.opacity = 1;
});
       

document.addEventListener("click", function(e){
if(e.target.closest('.context_menu'))
return;
menu.style.opacity = 0;
});
.context_menu{


width:70px;
background:lightgrey;
padding:5px;
opacity :0;
}
.context_menu div{
margin:5px;
background:grey;


}
.context_menu div:hover{
margin:5px;
background:red;
cursor:pointer;


}
<div class="context_menu">
<div>menu 1</div>
<div>menu 2</div>
</div>

额外的 CSS

var menu= document.querySelector('.context_menu');
document.addEventListener("contextmenu", function(e) {
e.preventDefault();
menu.style.position = 'absolute';
menu.style.left = e.pageX + 'px';
menu.style.top = e.pageY + 'px';
menu.style.opacity = 1;
});
       

document.addEventListener("click", function(e){
if(e.target.closest('.context_menu'))
return;
menu.style.opacity = 0;
});
.context_menu{


width:120px;
background:white;
border:1px solid lightgrey;


opacity :0;
}
.context_menu div{
padding:5px;
padding-left:15px;
margin:5px 2px;
border-bottom:1px solid lightgrey;
}
.context_menu div:last-child {
border:none;
}
.context_menu div:hover{


background:lightgrey;
cursor:pointer;


}
<div class="context_menu">
<div>menu 1</div>
<div>menu 2</div>
<div>menu 3</div>
<div>menu 4</div>
</div>