使用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
,我们将传入一个包含两个属性的设置对象:
-
menuSelector
采用我们之前在HTML中创build的菜单的jQueryselect器。 -
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()
来定位元素。- 我们需要确定它的
position
是absolute
。 - 然后,我们将使用事件的
pageX
和pageY
属性设置左侧和顶部位置。
- 我们需要确定它的
- 最后,为了防止右键单击操作打开它自己的菜单,我们将
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://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; } },