Fazendo menus de contexto personalizados com o botão direito do mouse para meu aplicativo da web

Tenho alguns sites como google-docs e map-quest que possuem menus suspensos personalizados quando você clica com o botão direito do mouse. De alguma forma, eles substituem o comportamento do menu suspenso do navegador, e agora estou certo de como eles fazem isso. Eu encontrei um plugin jQuery que faz isso, mas ainda estou curioso sobre algumas coisas:

  • Como é que isso funciona? O menu suspenso do navegador está realmente sendo substituído ou o efeito acabou de ser simulado? Se sim, como?
  • O que o plugin abstrai? O que está acontecendo nos bastidores?
  • Essa é a única maneira de conseguir esse efeito?

imagem do menu de contexto personalizado

Veja vários menus de contexto personalizados em ação

Eu sei que esta pergunta é muito antiga, mas acabei com o mesmo problema e resolvi-me, por isso estou respondendo no caso de alguém encontrar isso através do google como eu fiz. Eu baseei a minha solução no de Andrew, mas basicamente modifiquei tudo depois.

EDIT : ver o quão popular isso tem sido ultimamente, decidi atualizar também os estilos para torná-lo mais parecido com 2014 e menos como o Windows 95. Eu consertei os bugs @Quantico e @Trengot manchado então agora é uma resposta mais sólida.

EDIT 2 : Eu configuro com StackSnippets como eles são um novo recurso muito legal. Deixo aqui o bom jsfiddle para um pensamento de referência (clique no quarto painel para vê-los funcionar).

Novo snippet de pilha:

// 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; } 
   
  • First thing
  • Second thing
  • Third thing
Right click me

Como Adrian disse, os plugins vão funcionar da mesma maneira. Existem três partes básicas que você vai precisar:

1: Manipulador de events para 'contextmenu' evento 'contextmenu' :

 $(document).bind("contextmenu", function(event) { event.preventDefault(); $("
Custom menu
") .appendTo("body") .css({top: event.pageY + "px", left: event.pageX + "px"}); });

Aqui, você pode vincular o manipulador de events a qualquer seletor para o qual deseja exibir um menu. Eu escolhi o documento inteiro.

2: Manipulador de events para 'click' evento 'click' (para fechar o menu personalizado):

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

3: CSS para controlar a posição do menu:

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

O importante com o CSS é include o z-index e position: absolute

Não seria muito difícil envolver tudo isso em um plugin do jQuery.

Você pode ver uma demonstração simples aqui: http://jsfiddle.net/andrewwhitaker/fELma/

    Right Click       Right Click Me    

O menu de contexto do navegador está sendo substituído. Não há como aumentar o menu de contexto nativo em qualquer navegador principal.

Como o plug-in está criando seu próprio menu, a única parte que realmente está sendo abstraída é o evento do menu de contexto do navegador. O plug-in cria um menu html com base na sua configuração e coloca esse conteúdo no local do seu clique.

Sim, esta é a única maneira de criar um menu de contexto personalizado. Obviamente, plugins diferentes fazem coisas um pouco diferentes, mas todos eles irão replace o evento do navegador e colocar seu próprio menu baseado em html no local correto.

aqui está um exemplo para o menu de contexto do botão direito do mouse em javascript: Menu de contexto do botão direito

Usado o código javasScript bruto para a funcionalidade do menu de contexto. Você pode por favor verificar isso, espero que isso ajude você.

Código Vivo:

 (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 ***********/ 
     

Thumbnail Gallery (Right click to see the context menu)


Você pode assistir a este tutorial: http://www.youtube.com/watch?v=iDyEfKWCzhg Certifique-se de que o menu de contexto esteja oculto no início e tenha uma posição absoluta. Isso garantirá que não haverá vários menus de contexto e criação inútil do menu de contexto. O link para a página é colocado na descrição do vídeo do YouTube.

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

Eu sei que isso é bastante antigo também. Recentemente, tive a necessidade de criar um menu de contexto que eu injetasse em outros sites que tivessem propriedades diferentes com base no elemento clicado.

É bastante difícil, e provavelmente há maneiras melhores de conseguir isso. Ele usa o menu de contexto do jQuery Library Located Here

Eu gostei de criá-lo e apesar de que vocês podem ter algum uso disso.

Aqui está o violino . Espero que possa ajudar alguém lá fora.

 $(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() }; } }); }); 
    Intereting Posts