it-swarm.com.de

Verwenden Sie das Dropdown-Menü Bootstrap 3 als Kontextmenü

Wie kann ich mit Bootstrap 3 das Dropdown-Menü am Cursor platzieren und über den Code öffnen?

Ich muss es in einer Tabelle als Kontextmenü für seine Zeilen verwenden.

69
MojoDK

Es ist möglich. Ich habe Sie zu einer funktionierenden Demo gemacht, um einen guten Start zu ermöglichen.

Arbeitsdemo (Klicken Sie mit der rechten Maustaste auf eine beliebige Tabellenzeile, um sie in Aktion zu sehen)

Erstellen Sie zuerst Ihr Dropdown-Menü, blenden Sie es aus und ändern Sie sein position in absolute:

#contextMenu {
  position: absolute;
  display:none;
}

Binden Sie dann ein contextmenu -Ereignis an Ihre Tabellenzeilen, sodass Dropdown-/Kontextmenü angezeigt wird, und positionieren Sie es am Cursor:

var $contextMenu = $("#contextMenu");

$("body").on("contextmenu", "table tr", function(e) {
   $contextMenu.css({
      display: "block",
      left: e.pageX,
      top: e.pageY
   });
   return false;
});

Wenn der Benutzer eine Option auswählt, wird das Dropdown-/Kontextmenü ausgeblendet:

$contextMenu.on("click", "a", function() {
   $contextMenu.hide();
});
90
letiagoalves

Ich wollte nur verbessern letiagoalves tolle Antwort mit ein paar weiteren Vorschlägen.
Hier ist eine exemplarische Vorgehensweise zum Hinzufügen eines Kontextmenüs zu einem HTML-Element.

Beginnen wir mit einer funktionierenden Demo in jsFiddle

Markup:

Zuerst fügen wir ein Menü aus dem Bootstrap-Dropdown-Steuerelement hinzu. Fügen Sie es an einer beliebigen Stelle zu Ihrem HTML-Code hinzu, vorzugsweise auf der Stammebene des Körpers. Die .dropdown-menu-Klasse setzt display:none, sodass es anfänglich unsichtbar ist.
Es sollte so aussehen:

<ul id="contextMenu" class="dropdown-menu" role="menu">
    <li><a tabindex="-1" href="#">Action</a></li>
    <li><a tabindex="-1" href="#">Another action</a></li>
    <li><a tabindex="-1" href="#">Something else here</a></li>
    <li class="divider"></li>
    <li><a tabindex="-1" href="#">Separated link</a></li>
</ul>

Erweiterungseinstellungen:

Um unser Design modular zu halten, fügen wir unseren JavaScript-Code als jQuery-Erweiterung mit dem Namen contextMenu hinzu.

Wenn wir $.contextMenu aufrufen, übergeben wir ein Einstellungsobjekt mit zwei Eigenschaften:

  1. menuSelector verwendet den jQuery-Selektor des Menüs, das wir zuvor in HTML erstellt haben.
  2. menuSelected wird aufgerufen, wenn auf die Kontextmenüaktion geklickt wird.
$("#myTable").contextMenu({
    menuSelector: "#contextMenu",
    menuSelected: function (invokedOn, selectedMenu) {
        // context menu clicked
    });
});

Plugin-Vorlage:

Basierend auf der jQuery-Boilerplate-Plugin-Vorlage verwenden wir einen direkt aufgerufenen Funktionsausdruck , damit der globale Namespace nicht durcheinander gebracht wird. Da wir Abhängigkeiten von jQuery haben und Zugriff auf das Fenster benötigen, übergeben wir sie als Variablen, damit wir die Minimierung überleben können. Es wird so aussehen:

(function($, window){

    $.fn.contextMenu = function(settings) {  
        return this.each(function() {  
            // Code Goes Here
        }  
    };

})(jQuery, window);

Okay, keine Klempnerarbeiten mehr. Hier ist das Fleisch der Funktion:

Rechtsklickereignisse behandeln:

Wir werden das Ereignis contextmenu mouse für das Objekt behandeln, das die Erweiterung aufgerufen hat. Wenn das Ereignis ausgelöst wird, greifen wir auf das Dropdown-Menü zu, das wir zu Beginn hinzugefügt haben. Wir finden es anhand der Auswahlzeichenfolge, die bei der Initialisierung der Funktion von den Einstellungen übergeben wurde. Das Menü wird folgendermaßen geändert:

  • Wir greifen auf die Eigenschaft e.target zu und speichern sie als Datenattribut mit dem Namen invokedOn, damit wir später das Element identifizieren können, das das Kontextmenü ausgelöst hat.
  • Mit .show() schalten wir die Anzeige des Menüs auf sichtbar um.
  • Wir positionieren das Element mit .css().
    • Wir müssen sicherstellen, dass position auf absolute gesetzt ist.
    • Dann legen wir die linke und obere Position mithilfe der Eigenschaften pageX und pageY des Ereignisses fest.
  • Um zu verhindern, dass die Rechtsklick-Aktion ein eigenes Menü öffnet, return false verhindern wir, dass Javascript etwas anderes verarbeitet.

Es wird so aussehen:

$(this).on("contextmenu", function (e) {
    $(settings.menuSelector)
        .data("invokedOn", $(e.target))
        .show()
        .css({
            position: "absolute",
            left: e.pageX,
            top: e.pageY
        });

    return false;
});

Fix Menu Edge Cases:

Dies öffnet das Menü rechts unten neben dem Cursor, der es geöffnet hat. Wenn sich der Cursor jedoch auf ganz rechts auf dem Bildschirm befindet, sollte sich das Menü nach links öffnen. Befindet sich der Cursor ebenfalls unten, sollte sich das Menü oben öffnen. Es ist auch wichtig, zwischen dem Ende des window zu unterscheiden, das den physischen Frame enthält, und dem Ende des document, das das gesamte HTML-DOM darstellt und weit darüber hinaus scrollen kann das Fenster.

Um dies zu erreichen, legen wir den Speicherort mithilfe der folgenden Funktionen fest:

Wir nennen sie so:

.css({
    left: getMenuPosition(e.clientX, 'width', 'scrollLeft'),
    top: getMenuPosition(e.clientY, 'height', 'scrollTop')
});

Welches wird diese Funktion aufrufen, um die entsprechende Position zurückzugeben:

function getMenuPosition(mouse, direction, scrollDir) {
    var win = $(window)[direction](),
        scroll = $(window)[scrollDir](),
        menu = $(settings.menuSelector)[direction](),
        position = mouse + scroll;

    // opening menu would pass the side of the page
    if (mouse + menu > win && menu < mouse) 
        position -= menu;

    return position
}

Bindeklickereignisse im Menüelement:

Nachdem wir das Kontextmenü angezeigt haben, müssen wir eine Ereignisbehandlungsroutine hinzufügen, um auf Klickereignisse zu warten. Wir entfernen alle anderen Bindungen, die möglicherweise bereits hinzugefügt wurden, damit dasselbe Ereignis nicht zweimal ausgelöst wird. Diese können immer dann auftreten, wenn das Menü geöffnet wurde, aber aufgrund von Anklicken wurde nichts ausgewählt. Anschließend können wir dem Ereignis click eine neue Bindung hinzufügen, in der wir die Logik im nächsten Abschnitt behandeln.

Als Valepu vermerkt möchten wir keine Klicks auf etwas anderes als Menüelemente registrieren. Deshalb richten wir einen delegierten Handler ein, indem wir einen Selektor an on übergeben. Funktion, die "die Nachkommen der ausgewählten Elemente filtert, die das Ereignis auslösen".

Bisher sollte die Funktion so aussehen:

$(settings.menuSelector)
    .off('click')
    .on( 'click', "a", function (e) {
        //CODE IN NEXT SECTION GOES HERE
});

Menüklicks verarbeiten

Sobald wir wissen, dass ein Klick im Menü aufgetreten ist, werden wir die folgenden Dinge tun: Wir werden das Menü mit .hide() vom Bildschirm ausblenden. Als Nächstes möchten wir das Element, auf dem das Menü ursprünglich aufgerufen wurde, sowie die Auswahl aus dem aktuellen Menü speichern. Zum Schluss lösen wir die Funktionsoption aus, die an die Erweiterung übergeben wurde, indem wir .call() für die Eigenschaft verwenden und die Ereignisziele als Argumente übergeben.

$menu.hide();

var $invokedOn = $menu.data("invokedOn");
var $selectedMenu = $(e.target);

settings.menuSelected.call($(this), $invokedOn, $selectedMenu);

Ausblenden, wenn deaktiviert:

Schließlich möchten wir, wie bei den meisten Kontextmenüs, das Menü schließen, wenn ein Benutzer darauf klickt. Zu diesem Zweck warten wir auf Klickereignisse auf dem Body und schließen das Kontextmenü, wenn es folgendermaßen geöffnet ist:

$('body').click(function () {
    $(settings.menuSelector).hide();
});

Hinweis : Dank Sadhirs Kommentar löst Firefox Linux das click-Ereignis auf document während eines Rechtsklicks aus Sie müssen den Listener auf body einstellen.

Beispielsyntax:

Die Erweiterung wird mit dem ursprünglichen Objekt zurückgegeben, das das Kontextmenü und den angeklickten Menüpunkt ausgelöst hat. Möglicherweise müssen Sie mit jQuery dom durchqueren etwas Bedeutendes aus den Ereigniszielen herausfinden, dies sollte jedoch eine gute Basisfunktionalitätsebene bieten.

Hier ist ein Beispiel, um Informationen zu dem ausgewählten Element und der ausgewählten Aktion zurückzugeben:

$("#myTable").contextMenu({
    menuSelector: "#contextMenu",
    menuSelected: function (invokedOn, selectedMenu) {
        var msg = "You selected the menu item '" + 
                  selectedMenu.text() +
                  "' on the value '" + 
                  invokedOn.text() + "'";
        alert(msg);
    }
});

Bildschirmfoto:

Context Menu Screenshot

Update Hinweis:

Diese Antwort wurde erheblich aktualisiert, indem sie in eine jQuery-Erweiterungsmethode eingeschlossen wurde. Wenn Sie mein Original sehen möchten, können Sie den Beitragshistorie anzeigen, aber ich glaube, diese endgültige Version verwendet viel bessere Codierungsmethoden.

Bonusfunktion :

Wenn Sie einige nützliche Funktionen für Poweruser oder sich selbst beim Entwickeln von Funktionen hinzufügen möchten, können Sie das Kontextmenü umgehen, das auf Tastenkombinationen basiert, die beim Klicken mit der rechten Maustaste gedrückt werden. Zum Beispiel, wenn Sie möchten, dass das ursprüngliche Browserkontextmenü angezeigt wird, wenn Sie gedrückt halten Ctrlkönnen Sie dies als erste Zeile des contextMenu-Handlers hinzufügen:

// return native menu if pressing control
if (e.ctrlKey) return;
143
KyleMit

Einige Änderungen am KyleMit Code hinzugefügt:

  • handler "auf Dokument klicken" von "foreach" verschoben
  • "foreach" entfernt, einfach Event zum Selektor hinzufügen
  • menü auf "Dokumentenkontextmenü" verbergen
  • vorübergehende Ereignisse

    $("#myTable tbody td").contextMenu({
    menuSelector: "#contextMenu",
    menuSelected: function (invokedOn, selectedMenu) {
        var msg = "You selected the menu item '" + selectedMenu.text() +
            "' on the value '" + invokedOn.text() + "'";
        alert(msg);
    },
    onMenuShow: function(invokedOn) {
        var tr = invokedOn.closest("tr");
        $(tr).addClass("warning");
    },
    onMenuHide: function(invokedOn) {
        var tr = invokedOn.closest("tr");
        $(tr).removeClass("warning");
    } });
    

http://jsfiddle.net/dmitry_far/cgqft4k3/

6
Far Dmitry