javascript - Hur man lägger till en anpassad högerklicksmeny på en webbsida?


Jag vill lägga till en anpassad högerklicksmeny i min webbapplikation. Kan detta göras utan att använda några färdiga bibliotek? Om så är fallet, hur visar man en enkel anpassad högerklicksmeny som inte använder ett tredjeparts JavaScript-bibliotek?

Jag siktar på något liknande det Google Docs gör. Det låter användare högerklicka och visa användarna deras egen meny.

OBS: Jag vill lära mig hur man gör mitt eget istället för att använda något som någon annan redan har gjort eftersom de flesta gånger är dessa tredjepartsbibliotek överfyllda med funktioner medan jag bara vill ha funktioner som jag behöver, så jag vill att det ska vara helt handgjort av mig.

Svar #1

För att svara på din fråga - använd contextmenu-händelsen, som nedan:

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>

Men du borde fråga dig själv, vill du verkligen skriva över standardbeteendet för högerklick - det beror på vilken applikation du utvecklar.

JSFIDDLE

Svar #2

Var mycket användbart för mig. För folks skull som jag, som förväntar sig ritningen av menyn, lägger jag här koden jag använde för att göra högerklicksmenyn:

$(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="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.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>

Svar #3

En kombination av lite trevlig CSS och några icke-standard HTML-taggar utan externa bibliotek kan ge ett trevligt resultat (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>

Obs: menytaggen finns inte, jag hittar på den (du kan använda vad som helst)

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 är bara för detta exempel, jag tar personligen bort det för permanenta menyer på 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);

Observera också att du eventuellt kan ändra menu > menu{left:100%;} till menu > menu{right:100%;} för en meny som expanderar från höger till vänster. Du skulle dock behöva lägga till en marginal eller något någonstans.

Svar #4

Enligt svaren här och på andra 'flows' har jag gjort en version som liknar den i Google Chrome, med css3-övergång. JS Fiddle

Låt oss börja enkelt, eftersom vi har JS ovan på denna sida, kan vi oroa oss för CSS och layouten. Layouten som vi kommer att använda är ett <a>-element med ett <img>-element eller en Font Awesome-ikon (<i class="fa fa-flag"></i>) och ett <span> för att visa tangentbordsgenvägarna. Så här är strukturen:

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

Vi kommer att lägga dessa i en div och visa den diven vid högerklick. Låt oss stilisera dem som i Google Chrome, eller hur?

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

Nu kommer vi att lägga till koden från det accepterade svaret och få X- och Y-värdet för markören. För att göra detta kommer vi att använda e.clientX och e.clientY. Vi använder klient, så menydelen måste vara fast.

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

Och det är allt! Lägg bara till CSS-övergångarna för att tona in och ut, och klart!

var i = document.getElementById("menu").style;
if (document.addEventListener) {
  document.addEventListener('contextmenu', function(e) {
    var posX = e.clientX;
    var posY = e.clientY;
    menu(posX, posY);
    e.preventDefault();
  }, false);
  document.addEventListener('click', function(e) {
    i.opacity = "0";
    setTimeout(function() {
      i.visibility = "hidden";
    }, 501);
  }, false);
} else {
  document.attachEvent('oncontextmenu', function(e) {
    var posX = e.clientX;
    var posY = e.clientY;
    menu(posX, posY);
    e.preventDefault();
  });
  document.attachEvent('onclick', function(e) {
    i.opacity = "0";
    setTimeout(function() {
      i.visibility = "hidden";
    }, 501);
  });
}

function menu(x, y) {
  i.top = y + "px";
  i.left = x + "px";
  i.visibility = "visible";
  i.opacity = "1";
}
body {
  background: white;
  font-family: sans-serif;
  color: #5e5e5e;
}

#menu {
  visibility: hidden;
  opacity: 0;
  position: fixed;
  background: #fff;
  color: #555;
  font-family: sans-serif;
  font-size: 11px;
  -webkit-transition: opacity .5s ease-in-out;
  -moz-transition: opacity .5s ease-in-out;
  -ms-transition: opacity .5s ease-in-out;
  -o-transition: opacity .5s ease-in-out;
  transition: opacity .5s ease-in-out;
  -webkit-box-shadow: 2px 2px 2px 0px rgba(143, 144, 145, 1);
  -moz-box-shadow: 2px 2px 2px 0px rgba(143, 144, 145, 1);
  box-shadow: 2px 2px 2px 0px rgba(143, 144, 145, 1);
  padding: 0px;
  border: 1px solid #C6C6C6;
}

#menu a {
  display: block;
  color: #555;
  text-decoration: none;
  padding: 6px 8px 6px 30px;
  width: 250px;
  position: relative;
}

#menu a img,
#menu a i.fa {
  height: 20px;
  font-size: 17px;
  width: 20px;
  position: absolute;
  left: 5px;
  top: 2px;
}

#menu a span {
  color: #BCB1B3;
  float: right;
}

#menu a:hover {
  color: #fff;
  background: #3879D9;
}

#menu hr {
  border: 1px solid #EBEBEB;
  border-bottom: 0;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet"/>
<h2>CSS3 and JAVASCRIPT custom menu.</h2>
<em>Stephan Stanisic | Lisence free</em>
<p>Right-click anywhere on this page to open the custom menu. Styled like the Google Chrome contextmenu. And yes, you can use <i class="fa fa-flag"></i>font-awesome</p>
<p style="font-size: small">
  <b>Lisence</b>
  <br /> "THE PIZZA-WARE LICENSE" (Revision 42):
  <br /> You can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a Pizza in return.
  <br />
  <a style="font-size:xx-small" href="https://github.com/KLVN/UrbanDictionary_API#license">https://github.com/KLVN/UrbanDictionary_API#license</a>
</p>
<br />
<br />
<small>(The white body background is just because I hate the light blue editor background on the result on jsfiddle)
<div id="menu">
  <a href="#">
    <img src="http://puu.sh/nr60s/42df867bf3.png" /> AdBlock Plus <span>Ctrl + ?!</span>
  </a>
  <a href="#">
    <img src="http://puu.sh/nr5Z6/4360098fc1.png" /> SNTX <span>Ctrl + ?!</span>
  </a>
  <hr />
  <a href="#">
    <i class="fa fa-fort-awesome"></i> Fort Awesome <span>Ctrl + ?!</span>
  </a>
  <a href="#">
    <i class="fa fa-flag"></i> Font Awesome <span>Ctrl + ?!</span>
  </a>
</div>

Svar #5

Enkelaste startfunktionen, skapa en kontextmeny vid markörens position, som förstör sig själv när musen lämnar den.

oncontextmenu = (e) => {
  e.preventDefault()
  let menu = document.createElement("div")
  menu.id = "ctxmenu"
  menu.style = `top:${e.pageY-10}px;left:${e.pageX-40}px`
  menu.onmouseleave = () => ctxmenu.outerHTML = ''
  menu.innerHTML = "<p>Option1</p><p>Option2</p><p>Option3</p><p>Option4</p><p onclick='alert(`Thank you!`)'>Upvote</p>"
  document.body.appendChild(menu)
}
#ctxmenu {
  position: fixed;
  background: ghostwhite;
  color: black;
  cursor: pointer;
  border: 1px black solid
}

#ctxmenu > p {
  padding: 0 1rem;
  margin: 0
}

#ctxmenu > p:hover {
  background: black;
  color: ghostwhite
}

Svar #6

Ren JS- och CSS-lösning för en riktigt dynamisk högerklicksmeny, om än baserad på fördefinierade namngivningskonventioner för elementens id, länkar etc. jsfiddle och koden som du kan kopiera och klistra in på en enda statisk HTML-sida:

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())
  }
}
.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;
}
<!-- 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>

Svar #7

Du kan försöka blockera snabbmenyn genom att lägga till följande i din body-tagg:

<body oncontextmenu="return false;">

Detta kommer att blockera all åtkomst till snabbmenyn (inte bara från höger musknapp utan även från tangentbordet).

P.S. du kan lägga till detta på vilken tagg som helst om du vill inaktivera snabbmenyn

till exempel:

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

Kommer att inaktivera kontextmenyn i just den div:en

Svar #8

<!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>

Testad och fungerar i Opera 11.6, Firefox 9.01, Internet Explorer 9 och Chrome 17

Svar #9

Prova detta:

var cls = true;
var ops;

window.onload = function() {
    document.querySelector(".container").addEventListener("mouseenter", function() {
        cls = false;
    });
    document.querySelector(".container").addEventListener("mouseleave", function() {
        cls = true;
    });
    ops = document.querySelectorAll(".container td");
    for (let i = 0; i < ops.length; i++) {
        ops[i].addEventListener("click", function() {
            document.querySelector(".position").style.display = "none";
        });
    }

    ops[0].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 1!");
        }, 50);
    });

    ops[1].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 2!");
        }, 50);
    });

    ops[2].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 3!");
        }, 50);
    });

    ops[3].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 4!");
        }, 50);
    });

    ops[4].addEventListener("click", function() {
        setTimeout(function() {
            /* YOUR FUNCTION */
            alert("Alert 5!");
        }, 50);
    });
}

document.addEventListener("contextmenu", function() {
    var e = window.event;
    e.preventDefault();
    document.querySelector(".container").style.padding = "0px";

    var x = e.clientX;
    var y = e.clientY;

    var docX = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || document.body.offsetWidth;
    var docY = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || document.body.offsetHeight;

    var border = parseInt(getComputedStyle(document.querySelector(".container"), null).getPropertyValue('border-width'));

    var objX = parseInt(getComputedStyle(document.querySelector(".container"), null).getPropertyValue('width')) + 2;
    var objY = parseInt(getComputedStyle(document.querySelector(".container"), null).getPropertyValue('height')) + 2;

    if (x + objX > docX) {
        let diff = (x + objX) - docX;
        x -= diff + border;
    }

    if (y + objY > docY) {
        let diff = (y + objY) - docY;
        y -= diff + border;
    }

    document.querySelector(".position").style.display = "block";

    document.querySelector(".position").style.top = y + "px";
    document.querySelector(".position").style.left = x + "px";
});

window.addEventListener("resize", function() {
    document.querySelector(".position").style.display = "none";
});

document.addEventListener("click", function() {
    if (cls) {
        document.querySelector(".position").style.display = "none";
    }
});

document.addEventListener("wheel", function() {
    if (cls) {
        document.querySelector(".position").style.display = "none";
        static = false;
    }
});
.position {
    position: absolute;
    width: 1px;
    height: 1px;
    z-index: 2;
    display: none;
}

.container {
    width: 220px;
    height: auto;
    border: 1px solid black;
    background: rgb(245, 243, 243);
}

.container p {
    height: 30px;
    font-size: 18px;
    font-family: arial;
    width: 99%;
    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;
    background: rgb(245, 243, 243);
    color: black;
    transition: 0.2s;
}

.container p:hover {
    background: lightblue;
}

td {
    font-family: arial;
    font-size: 20px;
}

td:hover {
    background: lightblue;
    transition: 0.2s;
    cursor: pointer;
}
<div class="position">
    <div class="container" align="center">
        <table style="text-align: left; width: 99%; margin-left: auto; margin-right: auto;" border="0" cellpadding="2" cellspacing="2">
            <tbody>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 1<br>
                    </td>
                </tr>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 2<br>
                    </td>
                </tr>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 3<br>
                    </td>
                </tr>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 4<br>
                    </td>
                </tr>
                <tr>
                    <td style="vertical-align: middle; text-align: center;">Option 5<br>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

Relaterade artiklar