使用Bootstrap 3下拉菜单作为上下文菜单

使用引导程序3,我怎样才能将下拉菜单放在光标处并从代码中打开它?

我需要使用它作为其行的上下文菜单的表。

有可能的。 我给你做了一个工作演示,给你一个好的开始。

工作演示 (右键单击任何表行查看它的行动)

首先创build您的下拉菜单,将其隐藏并将其position更改为absolute

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

然后将一个contextmenu事件绑定到你的表格行,这样它就会显示下拉菜单和上下文菜单,并将它放在光标处:

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

然后,当用户select一个选项隐藏下拉菜单/上下文菜单:

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

我只是想改善letiagoalves伟大的答案,还有一些build议。
以下是如何将上下文菜单添加到任何html元素的演练。

让我们开始在jsFiddle中进行一个工作演示

标记:

首先,我们从引导下拉控件添加一个菜单。 将它添加到您的HTML的任何地方,最好在身体的根级别。 .dropdown-menu类将设置display:none所以它最初是不可见的。
它应该是这样的:

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

分机设置:

为了保持我们的devise模块化,我们将我们的JavaScript代码添加为名为contextMenu的jQuery扩展。

当我们调用$.contextMenu ,我们将传入一个包含两个属性的设置对象:

  1. menuSelector采用我们之前在HTML中创build的菜单的jQueryselect器。
  2. menuSelected将在单击上下文菜单动作时被调用。
 $("#myTable").contextMenu({ menuSelector: "#contextMenu", menuSelected: function (invokedOn, selectedMenu) { // context menu clicked }); }); 

插件模板:

基于jQuery样板插件模板 ,我们将使用立即调用函数expression式,这样我们就不会混淆全局名称空间。 由于我们依赖于jQuery并需要访问窗口,所以我们将它们作为variables传递,以便我们可以在缩小的情况下生存。 它看起来像这样:

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

好吧,没有更多的pipe道。 这是function的肉:

处理右键单击事件:

我们将在调用扩展的对象上处理contextmenu鼠标事件。 事件触发时,我们将抓取我们在开始时添加的下拉菜单。 当我们初始化函数时,我们将使用由设置传入的select器string来定位它。 我们将通过执行以下操作来修改菜单:

  • 我们将获取e.target属性并将其存储为一个名为invokedOn的数据属性,以便稍后可以确定引发上下文菜单的元素。
  • 我们将菜单的显示切换到可见使用.show()
  • 我们将使用.css()来定位元素。
    • 我们需要确定它的positionabsolute
    • 然后,我们将使用事件的pageXpageY属性设置左侧和顶部位置。
  • 最后,为了防止右键单击操作打开它自己的菜单,我们将return false来停止处理其他任何事情的JavaScript。

它看起来像这样:

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

修复菜单边缘情况:

这将打开菜单到打开它的光标的右下angular。 但是,如果光标位于屏幕的最右侧 ,菜单应向左打开。 同样,如果光标在底部,菜单应该打开到顶部。 区分包含物理框架的window底部和代表整个html DOM的document底部,并且可以滚动到窗口之外也很重要。

为了实现这一点,我们将使用以下function来设置位置:

我们会这样称呼他们:

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

哪个会调用这个函数来返回适当的位置:

 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 } 

绑定菜单元素上的单击事件:

在我们显示上下文菜单之后,我们需要添加一个事件处理程序来监听点击事件。 我们将删除可能已经添加的任何其他绑定,以便我们不会触发相同的事件两次。 这些可以在菜单被打开的任何时候发生,但由于点击而没有被select。 然后,我们可以在click事件中添加一个新的绑定,我们将在下一节中处理这个逻辑。

正如valepu指出的那样 ,我们不想注册点击菜单项以外的任何东西,所以我们通过将select器传递给on函数来设置一个委托处理程序 ,该函数将“过滤触发事件的选定元素的后代”。

到目前为止,函数应该是这样的:

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

处理菜单点击

一旦我们知道菜单上发生了点击,我们将做以下事情:我们将使用.hide()从屏幕上隐藏菜单。 接下来,我们要保存菜单最初调用的元素以及当前菜单中的select。 最后,我们将通过在属性中使用.call().call()传递给扩展的函数选项,并将事件目标作为参数传入。

 $menu.hide(); var $invokedOn = $menu.data("invokedOn"); var $selectedMenu = $(e.target); settings.menuSelected.call($(this), $invokedOn, $selectedMenu); 

隐藏当点击closures:

最后,与大多数上下文菜单一样,我们还想在用户点击时closures菜单。 为此,我们将监听正文上的任何点击事件,并closures上下文菜单,如果它是这样打开的话:

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

注意 : 感谢Sadhir的评论 ,Firefox linux在右键单击时触发document上的单击事件,因此您必须在body上设置侦听器。

语法例子:

该扩展将返回与引发上下文菜单和被点击的菜单项的原始对象。 您可能必须使用jQuery 遍历dom来从事件目标中find有意义的东西,但这应该提供一个很好的基础function层。

以下是返回所选项目和操作信息的示例:

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

截图:

上下文菜单截图

更新注意:

这个答案已经被包装成了一个jQuery扩展方法。 如果你想看到我的原创,你可以查看发布的历史,但我相信这个最终版本使用更好的编码实践。

奖金特点

如果你想为高级用户添加一些不错的function,或者你自己在开发function,你可以绕过上下文菜单基于任何按键组合右键点击。 例如,如果您希望在按住Ctrl键的同时允许显示原始浏览器上下文菜单,则可以将其添加为contextMenu处理程序的第一行:

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

增加了对KyleMit代码的修改:

  • 从“foreach”移动“文档点击”处理程序
  • 删除“foreach”,只需将事件添加到select器
  • 隐藏菜单“文档上下文菜单”
  • 传递事件

     $("#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/

我发现这个简单和工作的上下文菜单。 我正在使用这个库http://swisnl.github.io/jQuery-contextMenu/index.html 。 希望能帮助到你

表:

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

上下文菜单:

  "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; } },