Web uygulamam için özel sağ tıklama bağlam menüleri yapmak


127

Sağ tıkladığınızda özel açılır menüleri olan google-docs ve map-quest gibi birkaç web sitem var. Bir şekilde tarayıcının açılır menü davranışını geçersiz kılıyorlar ve şimdi tam olarak nasıl yaptıklarından eminim. Bunu yapan bir jQuery eklentisi buldum , ancak yine de birkaç şeyi merak ediyorum:

  • Bu nasıl çalışıyor? Tarayıcının açılır menüsü gerçekten geçersiz kılınmış mı yoksa efekt sadece simüle edilmiş mi? Öyleyse nasıl?
  • Eklenti neyi soyutlamaktadır? Perde arkasında neler oluyor?
  • Bu etkiyi elde etmenin tek yolu bu mu?

özel bağlam menüsü resmi

Birkaç özel bağlam menüsünü çalışırken görün

Yanıtlar:


219

Bu sorunun çok eski olduğunu biliyorum, ancak aynı sorunu buldum ve kendim çözdüm, bu yüzden birisinin bunu benim yaptığım gibi google aracılığıyla bulması durumunda cevap veriyorum. Çözümümü @ Andrew'un çözümüne dayandırdım, ancak daha sonra temelde her şeyi değiştirdim.

DÜZENLEME : Son zamanlarda ne kadar popüler olduğunu görünce, stilleri de güncellemeye karar verdim, daha çok 2014 gibi ve daha az Windows 95 gibi görünmesini sağladım. @Quantico ve @Trengot tespit edilen hataları düzelttim, bu yüzden şimdi daha sağlam bir cevap.

DÜZENLEME 2 : Gerçekten harika ve yeni bir özellik oldukları için StackSnippets ile kurdum. İyi jsfiddle'ı referans düşüncesi için burada bırakıyorum (çalıştıklarını görmek için 4. panele tıklayın).

Yeni Yığın Parçacığı:

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

Not: Bazı küçük hatalar görebilirsiniz (imleçten uzakta bir açılır menü , vb.), Lütfen bunun jsfiddle'da çalıştığından emin olun , çünkü bu, web sayfanıza StackSnippets'ten daha benzer.


1
Sanırım fare indirme ile bir sorununuz olabilir. Bir menü öğesine tıklamak, fare indirme ve fare yukarı olan bir tıklamayı tetiklediğinden, yarış durumuna neden olabilir.
Quantico

2
Teşekkürler @Quantico, bu doğru ve şimdi hem kodda hem de jsfiddle'da düzeltilmesi gerekiyor. Başka bir sorun var mı? Sidenote: vay, jsfiddle'ın önceki 170 düzenlemesi, kesinlikle popüler oldu.
Francisco Presencia

1
Yeni keman kullanılırken, sayfada başka html öğeleri kullanıyorsanız açılır pencere şeffaf görünürse. DÜZENLEME: css'e arka plan rengi eklemek sorunu çözer.
Holloway

1
Bir başka küçük sorun: Menü görünür durumdayken bir yere sağ tıklarsanız, gösterilmeden önce titriyor. Ya gizlenmesi (varsayılan gibi) ya da gizlenmesi ve ardından yeni konumda görünmesi gerektiğini düşünüyorum.
Holloway

@ChetanJoshi, MDN'ye göre IE11 üzerinde çalışması gerektiği gibi görünüyor: developer.mozilla.org/en-US/docs/Web/Events/… Herhangi bir hata görüyor musunuz?
Francisco Presencia

63

Adrian'ın dediği gibi, eklentiler aynı şekilde çalışacak. İhtiyacınız olacak üç temel parça vardır:

1: Olay için 'contextmenu'olay işleyicisi :

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

Burada, olay işleyicisini, menüyü göstermek istediğiniz herhangi bir seçiciye bağlayabilirsiniz. Belgenin tamamını seçtim.

2: Olay için 'click'olay işleyici (özel menüyü kapatmak için):

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

3: Menünün konumunu kontrol etmek için CSS:

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

CSS ile ilgili önemli olan şey, z-indexveposition: absolute

Tüm bunları kaygan bir jQuery eklentisine sığdırmak çok zor olmaz.

Burada basit bir demo görebilirsiniz: http://jsfiddle.net/andrewwhitaker/fELma/


Bence bu bağlam menüsü, kullanıcı içine tıkladığında (ancak kullanıcı dışarıya tıkladığında kapanırsa) açık kalırsa daha kullanışlı olur. Bu şekilde çalışacak şekilde değiştirilebilir mi?
Anderson Green

2
event.targetTıklama bağlantısının içine bakarsınız document. İçerik menüsünde değilse, menüyü gizleyin: jsfiddle.net/fELma/286
Andrew Whitaker

2
Onu biraz değiştirdim (böylece birden fazla menünün aynı anda gösterilmesini engelleyecek şekilde): jsfiddle.net/fELma/287
Anderson Green

Radyal bir sağ tıklama bağlam menüsü oluşturmaya çalışıyorum (buradaki gibi: pushing-pixels.org/wp-content/uploads/2012/07/… ). Bu, nasıl devam edileceğini anlamak için harika bir başlangıç, teşekkürler!
Boris

@AndrewWhitaker cevabınız tüm belgeye uygulanacağını söylüyor. Ya belirli bir kontrole, örneğin bir düğmeye uygulanmasını istersem (kimliğinin button1 olduğunu varsayarak) ..?
Tk1993

8

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


4

javascript'te sağ tıklama bağlam menüsü için bir örnek: Sağ Tıklama Bağlam Menüsü

Bağlam menüsü işlevselliği için ham javasScript Kodu kullanıldı. Lütfen bunu kontrol eder misiniz, umarım bu size yardımcı olur.

Canlı Kod:

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


Vanilya JS ve temiz bir düzen kullanarak harika bir iş çıkardınız!
kurt

3

Tarayıcının içerik menüsü geçersiz kılınıyor. Herhangi bir ana tarayıcıda yerel bağlam menüsünü genişletmenin bir yolu yoktur.

Eklenti kendi menüsünü oluşturduğundan, gerçekten soyutlanan tek kısım tarayıcının bağlam menüsü olayıdır. Eklenti, yapılandırmanıza bağlı olarak bir html menüsü oluşturur ve ardından bu içeriği tıkladığınız yere yerleştirir.

Evet, özel bir bağlam menüsü oluşturmanın tek yolu budur. Açıkçası, farklı eklentiler işleri biraz farklı yapar, ancak hepsi tarayıcının olayını geçersiz kılar ve kendi html tabanlı menülerini doğru yere yerleştirir.


2
Firefox'un artık HTML5 yerel 'bağlam menüsü' (biçimlendirme yoluyla bildirildi) için destek eklediğini belirtmek isterim. Artık Firefox 8 beta sürümünde mevcuttur. ( developer.mozilla.org/en/Firefox_8_for_developers ).
poshaughnessy

2

Bu eğiticiyi izleyebilirsiniz: http://www.youtube.com/watch?v=iDyEfKWCzhg Bağlam menüsünün ilk başta gizlendiğinden ve mutlak bir konuma sahip olduğundan emin olun. Bu, birden fazla bağlam menüsü ve bağlam menüsünün gereksiz yaratılmasının olmamasını sağlayacaktır. Sayfanın bağlantısı, YouTube videosunun açıklamasına yerleştirilir.

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

1

Bunun da oldukça eski olduğunu biliyorum. Son zamanlarda, tıklanan öğeye bağlı olarak farklı özelliklere sahip diğer sitelere enjekte ettiğim bir bağlam menüsü oluşturma ihtiyacım vardı.

Oldukça kaba ve bunu başarmanın muhtemelen daha iyi yolları var. JQuery Bağlam menüsü Burada Bulunan Kitaplığı kullanır

Ben onu yaratmaktan zevk aldım ve yine de sizler bundan yararlanabilirsiniz.

İşte keman . Umarım dışarıdaki birine yardım edebilir.

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

0

Bootstrap kullanarak aşağıdaki gibi güzel ve kolay bir uygulamaya sahibim.

<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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.