En utilisant Bootstrap 3, comment puis-je placer le menu déroulant au niveau du curseur et l'ouvrir à partir du code ?
J'ai besoin de l'utiliser sur un tableau comme un menu contextuel pour ses lignes.
En utilisant Bootstrap 3, comment puis-je placer le menu déroulant au niveau du curseur et l'ouvrir à partir du code ?
J'ai besoin de l'utiliser sur un tableau comme un menu contextuel pour ses lignes.
Je voulais juste améliorer letiagoalves excellente réponse avec quelques suggestions supplémentaires.
Voici comment ajouter un menu contextuel à n'importe quel élément html.
Tout d'abord, ajoutons un menu à partir de l'onglet contrôle de liste déroulante bootstrap . Ajoutez-le n'importe où dans votre HTML, de préférence au niveau de la racine du corps. Le site .dropdown-menu
va définir display:none
donc c'est initialement invisible.
Il devrait ressembler à ceci :
<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>
Pour garder notre conception modulaire, nous ajouterons notre code JavaScript comme une extension jQuery appelée contextMenu
.
Quand nous appelons $.contextMenu
nous allons passer un objet de paramètres avec 2 propriétés :
menuSelector
prend le sélecteur jQuery du menu que nous avons créé plus tôt en HTML.menuSelected
sera appelé lorsque l'action du menu contextuel sera cliquée.
$("#myTable").contextMenu({ menuSelector: "#contextMenu", menuSelected: function (invokedOn, selectedMenu) { // context menu clicked }); });
Sur la base du Modèle de plugin jQuery boilerplate nous utiliserons un Expression de la fonction immédiatement déclenchée pour ne pas embrouiller l'espace de nom global. Puisque nous avons des dépendances sur jQuery et que nous avons besoin d'accéder à la fenêtre, nous allons les passer en tant que variables afin de survivre à la minification. Cela ressemblera à ceci :
(function($, window){
$.fn.contextMenu = function(settings) {
return this.each(function() {
// Code Goes Here
}
};
})(jQuery, window);
Nous allons nous occuper de la contextmenu
événement souris sur l'objet qui a appelé l'extension. Lorsque l'événement se déclenche, nous allons saisir le menu déroulant que nous avons ajouté au début. Nous allons le localiser en utilisant la chaîne de sélection passée par les paramètres lorsque nous avons initialisé la fonction. Nous allons modifier le menu en faisant ce qui suit :
e.target
et le stocker comme un attribut de données appelé invokedOn
afin de pouvoir identifier ultérieurement l'élément qui a fait apparaître le menu contextuel..show()
.css()
.
position
est réglé sur absolute
.pageX
y pageY
les propriétés de l'événement.return false
pour empêcher le javascript de gérer autre chose.Cela ressemblera à ceci :
$(this).on("contextmenu", function (e) {
$(settings.menuSelector)
.data("invokedOn", $(e.target))
.show()
.css({
position: "absolute",
left: e.pageX,
top: e.pageY
});
return false;
});
Cela ouvrira le menu en bas à droite du curseur qui l'a ouvert. Toutefois, si le curseur se trouve à la position à l'extrême droite de l'écran le menu devrait s'ouvrir sur la gauche. De même, si le curseur se trouve en bas, le menu doit s'ouvrir vers le haut. Il est également important de faire la différence entre le menu le bas de la window
qui contient le cadre physique, et le bas de l'écran. document
qui représente l'ensemble du DOM du html et peut défiler bien au-delà de la fenêtre.
Pour ce faire, nous allons définir l'emplacement en utilisant les fonctions suivantes :
On va les appeler comme ça :
.css({
left: getMenuPosition(e.clientX, 'width', 'scrollLeft'),
top: getMenuPosition(e.clientY, 'height', 'scrollTop')
});
qui appellera cette fonction pour retourner la position appropriée :
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
}
Après avoir affiché le menu contextuel, nous devons ajouter un gestionnaire d'événements pour écouter les événements de clics sur celui-ci. Nous supprimerons toute autre liaison qui aurait déjà été ajoutée afin de ne pas déclencher deux fois le même événement. Ces événements peuvent se produire chaque fois que le menu a été ouvert, mais que rien n'a été sélectionné en raison d'un clic. Ensuite, nous pouvons ajouter une nouvelle liaison sur l'élément click
où nous allons gérer la logique dans la section suivante.
Comme valepu a noté nous ne voulons pas enregistrer les clics sur d'autres éléments que les éléments de menu. gestionnaire délégué en passant un sélecteur dans la fonction on
qui va "filtrer les descendants des éléments sélectionnés qui déclenchent l'événement".
Jusqu'à présent, la fonction devrait ressembler à ceci :
$(settings.menuSelector)
.off('click')
.on( 'click', "a", function (e) {
//CODE IN NEXT SECTION GOES HERE
});
Une fois que nous savons qu'un clic a eu lieu sur le menu, nous allons faire les choses suivantes : Nous allons cacher le menu de l'écran avec .hide()
. Ensuite, nous voulons enregistrer l'élément sur lequel le menu a été invoqué à l'origine, ainsi que la sélection du menu actuel. Enfin, nous allons lancer l'option de fonction qui a été passée dans l'extension en utilisant la commande .call()
sur la propriété et en passant les cibles de l'événement comme arguments.
$menu.hide();
var $invokedOn = $menu.data("invokedOn");
var $selectedMenu = $(e.target);
settings.menuSelected.call($(this), $invokedOn, $selectedMenu);
Enfin, comme pour la plupart des menus contextuels, nous souhaitons également fermer le menu lorsqu'un utilisateur clique dessus. Pour ce faire, nous allons écouter tous les événements de clics sur le corps et fermer le menu contextuel s'il est ouvert comme ceci :
$('body').click(function () {
$(settings.menuSelector).hide();
});
Note : Merci au commentaire de Sadhir Firefox linux déclenche l'événement clic sur
document
lors d'un clic droit, vous devez donc configurer l'écouteur surbody
.
L'extension retournera avec l'objet original qui a soulevé le menu contextuel et l'élément de menu qui a été cliqué. Vous devrez peut-être traverser le dom en utilisant jQuery pour trouver quelque chose de significatif à partir des cibles des événements, mais cela devrait fournir une bonne couche de fonctionnalité de base.
Voici un exemple pour renvoyer des informations sur l'élément et l'action sélectionnés :
$("#myTable").contextMenu({
menuSelector: "#contextMenu",
menuSelected: function (invokedOn, selectedMenu) {
var msg = "You selected the menu item '" +
selectedMenu.text() +
"' on the value '" +
invokedOn.text() + "'";
alert(msg);
}
});
Cette réponse a été mise à jour de manière substantielle en l'enveloppant dans une méthode d'extension jQuery. Si vous voulez voir l'original, vous pouvez consulter l'historique des messages, mais je pense que cette version finale utilise de bien meilleures pratiques de codage.
Fonction bonus :
Si vous souhaitez ajouter une fonctionnalité intéressante pour les utilisateurs expérimentés ou pour vous-même en développant des fonctionnalités, vous pouvez contourner le menu contextuel en fonction de toute combinaison de touches maintenue lors du clic droit. Par exemple, si vous souhaitez que le menu contextuel du navigateur original s'affiche lorsque vous maintenez la touche Ctrl vous pourriez ajouter ceci comme première ligne du gestionnaire du menu contextuel :
// return native menu if pressing control
if (e.ctrlKey) return;
Comment éviter que le menu ne crée une barre de défilement horizontale s'il est cliqué près de l'extrémité droite/gauche de l'écran ? Par exemple, si nous avons cliqué trop près de l'extrémité droite de l'écran et que le menu s'ouvre, il s'ouvre à gauche en détectant qu'il est près de l'extrémité de l'écran et qu'il devrait s'ouvrir dans l'autre direction. J'entends par là que l'on peut ajouter intelligemment la fonction "pull-left" ou "pull-right" ?
Toute suggestion sur la façon de faire fonctionner cela sur plusieurs éléments plutôt que sur l'ensemble du tableau - c'est-à-dire les éléments <li> afin que seuls ceux-là soient cliquables. Si vous l'appliquez à chaque <tr> par exemple, la fonction de rappel pour l'élément sélectionné dans le menu est appelée plusieurs fois - jsfiddle.net/HLqTQ/1
C'est possible. Je vous ai fait une démo fonctionnelle pour vous donner un bon départ.
Démonstration de travail (Cliquez avec le bouton droit de la souris sur n'importe quelle ligne du tableau pour le voir en action)
Créez tout d'abord votre menu déroulant, cachez-le et modifiez son position
à absolute
:
#contextMenu {
position: absolute;
display:none;
}
Puis lier un contextmenu
aux lignes de votre tableau pour qu'il affiche le menu déroulant/contexte et le positionne au niveau du curseur :
var $contextMenu = $("#contextMenu");
$("body").on("contextmenu", "table tr", function(e) {
$contextMenu.css({
display: "block",
left: e.pageX,
top: e.pageY
});
return false;
});
Ensuite, lorsque l'utilisateur sélectionne une option, le menu déroulant/contexte est masqué :
$contextMenu.on("click", "a", function() {
$contextMenu.hide();
});
+1, Bonne réponse. Ma seule suggestion serait que, typiquement, les menus contextuels disparaissent pour tout clic n'importe où sur la page. J'ai ajouté à votre exemple dans ma réponse ci-dessous.
Merci :) J'ai remarqué cela, mais j'ai choisi de ne pas supposer plus que ce que le PO a demandé, bien qu'il le veuille probablement.
À l'intérieur du callback que vous pouvez utiliser : var $row = $(this)
ou si vous voulez seulement son id, il n'est pas nécessaire de créer un objet jQuery, il suffit de faire var id = this.id
J'ai fait un plugin de menu contextuel pour bootstrap. Regardez ça https://github.com/sydcanem/bootstrap-contextmenu .
Ajout de quelques modifications à KyleMit Le code de l'entreprise :
événements passagers
$("#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");
} });
J'ai trouvé ce menu contextuel simple et fonctionnel. J'utilise cette bibliothèque http://swisnl.github.io/jQuery-contextMenu/index.html . J'espère que cela vous aidera
table :
<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>
Menu contextuel :
"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;
}
},
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
0 votes
J'ai fait un plugin de menu contextuel pour bootstrap. Regardez ça github.com/sydcanem/bootstrap-contextmenu .