Wie kann ich mit Bootstrap 3 das Dropdown-Menü am Cursor platzieren und es aus dem Code öffnen?
Ich muss es in einer Tabelle als Kontextmenü für seine Zeilen verwenden.
Wie kann ich mit Bootstrap 3 das Dropdown-Menü am Cursor platzieren und es aus dem Code öffnen?
Ich muss es in einer Tabelle als Kontextmenü für seine Zeilen verwenden.
Antworten:
Es ist möglich. Ich habe dir eine funktionierende Demo gemacht, um einen guten Start zu ermöglichen.
Arbeitsdemo (Klicken Sie mit der rechten Maustaste auf eine Tabellenzeile, um sie in Aktion zu sehen.)
Erstellen Sie zuerst Ihr Dropdown-Menü, blenden Sie es aus und ändern Sie es position
in absolute
:
#contextMenu {
position: absolute;
display:none;
}
Binden Sie dann ein contextmenu
Ereignis an Ihre Tabellenzeilen, sodass das 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 zum Ausblenden des Dropdown- / Kontextmenüs auswählt:
$contextMenu.on("click", "a", function() {
$contextMenu.hide();
});
var $row = $(this)
oder wenn Sie nur seine ID möchten, müssen Sie kein jQuery-Objekt erstellen, tun var id = this.id
Ich wollte nur die großartige Antwort von letiagoalves mit ein paar weiteren Vorschlägen verbessern .
Hier finden Sie eine exemplarische Vorgehensweise zum Hinzufügen eines Kontextmenüs zu einem beliebigen HTML-Element.
Fügen wir zunächst ein Menü aus dem Dropdown-Steuerelement für den Bootstrap hinzu . Fügen Sie es irgendwo zu Ihrem HTML hinzu, vorzugsweise auf der Stammebene des Körpers. Die .dropdown-menu
Klasse wird display:none
so eingestellt, dass sie zunächst 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>
Um unser Design modular zu halten, fügen wir unseren JavaScript-Code als jQuery-Erweiterung mit dem Namen hinzu contextMenu
.
Wenn wir aufrufen $.contextMenu
, übergeben wir ein Einstellungsobjekt mit zwei Eigenschaften:
menuSelector
Nimmt den jQuery-Selektor des Menüs, das wir zuvor in HTML erstellt haben.menuSelected
wird aufgerufen, wenn auf die Kontextmenüaktion geklickt wird.$("#myTable").contextMenu({
menuSelector: "#contextMenu",
menuSelected: function (invokedOn, selectedMenu) {
// context menu clicked
});
});
Basierend auf der Plugin-Vorlage für das jQuery-Boilerplate verwenden wir einen sofort aufgerufenen Funktionsausdruck, damit wir den globalen Namespace nicht durcheinander bringen. Da wir Abhängigkeiten von jQuery haben und Zugriff auf das Fenster benötigen, werden wir diese als Variablen übergeben, 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);
Wir werden das contextmenu
Mausereignis 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 am Anfang hinzugefügt haben. Wir finden es anhand der Auswahlzeichenfolge, die bei der Initialisierung der Funktion von den Einstellungen übergeben wurde. Wir werden das Menü folgendermaßen ändern:
e.target
Eigenschaft und speichern sie als Datenattribut mit dem Namen invokedOn
, damit wir später das Element identifizieren können, das das Kontextmenü ausgelöst hat..show()
.css()
.
position
eingestellt ist absolute
. pageX
und pageY
-Eigenschaften des Ereignisses fest. return false
, dass das 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;
});
Dadurch wird das Menü rechts unten neben dem Cursor geöffnet, der es geöffnet hat. Befindet sich der Cursor jedoch ganz rechts auf dem Bildschirm , sollte sich das Menü ganz links öffnen. Wenn sich der Cursor unten befindet, sollte sich das Menü ebenfalls oben öffnen. Es ist auch wichtig, zwischen dem unteren Rand deswindow
, der den physischen Frame enthält, und dem unteren Rand des, der document
das gesamte HTML-DOM darstellt und weit über das Fenster hinaus scrollen kann, zu unterscheiden.
Um dies zu erreichen, legen wir den Speicherort mit den folgenden Funktionen fest:
Wir werden sie so nennen:
.css({
left: getMenuPosition(e.clientX, 'width', 'scrollLeft'),
top: getMenuPosition(e.clientY, 'height', 'scrollTop')
});
Was diese Funktion aufruft, 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
}
Nachdem wir das Kontextmenü angezeigt haben, müssen wir einen Ereignishandler hinzufügen, um auf Klickereignisse zu warten. Wir entfernen alle anderen Bindungen, die möglicherweise bereits hinzugefügt wurden, damit wir nicht dasselbe Ereignis zweimal auslösen. Diese können jederzeit auftreten, wenn das Menü geöffnet wurde, aber aufgrund des Klickens nichts ausgewählt wurde. Dann können wir dem click
Ereignis, in dem wir die Logik im nächsten Abschnitt behandeln , eine neue Bindung hinzufügen .
Wie valepu feststellte , möchten wir keine Klicks auf etwas anderes als Menüelemente registrieren. Daher richten wir einen delegierten Handler ein, indem wir einen Selektor an die on
Funktion übergeben, die "die Nachkommen der ausgewählten Elemente filtert, die das Ereignis auslösen".
Bisher sollte die Funktion folgendermaßen aussehen:
$(settings.menuSelector)
.off('click')
.on( 'click', "a", function (e) {
//CODE IN NEXT SECTION GOES HERE
});
Sobald wir wissen, dass ein Klick auf das Menü aufgetreten ist, werden wir die folgenden Dinge tun: Wir werden das Menü mit auf dem Bildschirm ausblenden .hide()
. Als nächstes wollen wir das Element speichern, für das das Menü ursprünglich aufgerufen wurde, sowie die Auswahl aus dem aktuellen Menü. Schließlich lösen wir die Funktionsoption aus, die an die Erweiterung übergeben wurde, indem wir sie .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);
Schließlich möchten wir, wie bei den meisten Kontextmenüs, das Menü schließen, wenn ein Benutzer ebenfalls darauf klickt. Dazu warten wir auf Klickereignisse im Body und schließen das Kontextmenü, wenn es wie folgt geöffnet ist:
$('body').click(function () {
$(settings.menuSelector).hide();
});
Hinweis : Dank Sadhirs Kommentar löst Firefox Linux das Klickereignis
document
bei einem Rechtsklick aus, sodass Sie den Listener einrichten müssenbody
.
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 den Dom mit jQuery durchlaufen , um aus den Ereigniszielen etwas Sinnvolles zu finden. Dies sollte jedoch eine gute Ebene der Basisfunktionalität bieten.
Hier ist ein Beispiel, um Informationen für das ausgewählte Element und die ausgewählte 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);
}
});
Diese Antwort wurde erheblich aktualisiert, indem sie in eine jQuery-Erweiterungsmethode eingeschlossen wurde. Wenn Sie mein Original sehen möchten, können Sie den Post-Verlauf anzeigen, aber ich glaube, dass diese endgültige Version viel bessere Codierungspraktiken verwendet.
Bonus-Funktion :
Wenn Sie bei der Entwicklung von Funktionen einige nützliche Funktionen für Poweruser oder sich selbst hinzufügen möchten, können Sie das Kontextmenü umgehen, basierend auf den Tastenkombinationen, die beim Klicken mit der rechten Maustaste gedrückt werden. Wenn Sie beispielsweise zulassen möchten, dass das ursprüngliche Browser-Kontextmenü beim Halten angezeigt wird Ctrl, können Sie dies als erste Zeile des contextMenu-Handlers hinzufügen:
// return native menu if pressing control
if (e.ctrlKey) return;
contextMenu
Plugin übergeben wurde, automatisch einen eigenen Klick-Handler im Menü-Popup hinzufügte. Sobald auf das Element geklickt wurde, wurde jeder Ereignishandler hintereinander ausgelöst. Um dies zu beheben, wird der Handler jetzt dynamisch zum Zeitpunkt der Behandlung des Rechtsklickereignisses hinzugefügt, sodass immer nur ein einziges Element für die Behandlung des Menüklicks verantwortlich ist.
document
aus, als ob es einige Probleme gibt, da das Dokument immer noch viel Platz hat, wenn es nicht nach unten gescrollt wird, sodass das Menü am unteren Rand des Fensters herunterfällt. Hier ist ein Beispiel für dieses Problem in der Geige . Es sieht so aus, als müssten Sie dies berücksichtigen $(window).scrollTop()
. Ich werde meine Antwort aktualisieren.
Einige Änderungen an KyleMits Code hinzugefügt :
Ereignisse passieren
$("#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");
} });
onMenuShow
. Beachten Sie auch, dass Sie am Ende $.fn.contextMenu = function (settings) {}
aufrufen sollten, return this;
da zu erwarten ist, dass jQuery-Methoden normalerweise verkettbar sind.
Ich fand dieses einfache und funktionierende Kontextmenü. Ich verwende diese Bibliothek http://swisnl.github.io/jQuery-contextMenu/index.html . Ich hoffe es hilft
Tabelle:
<table id="ppmpsupplies" class="table table-bordered table-hover" cellspacing="0" width="100%">
<thead>
<tr>
<th>Code</th>
<th>General Description</th>
<th>Unit</th>
<th>Quantity</th>
<th>Estimated Budget</th>
<th>Mode of Procurement</th>
</tr>
</thead>
<tbody>
<?php foreach($items as $item){?>
<tr>
<td><?php echo $item->id;?></td>
<td><?php echo $item->description;?></td>
<td><?php echo $item->unit;?></td>
<td><?php echo $item->quantity;?></td>
<td><?php echo $item->budget;?></td>
<td><?php echo $item->mode;?></td>
</tr>
<?php }?>
</tbody>
<tfoot>
<td colspan="3"></td>
<td>Total</td>
<td></td>
</tfoot>
</table>
Kontextmenü:
"edit": {
name: "Edit",
icon: "fa-pencil-square-o",
callback: function(item, id) {
return true;
}
},
"delete": {
name: "Delete",
icon: "fa-trash-o",
callback: function(item, id) {
return true;
}
},