使用Bootstrap 3,如何将下拉菜单放在光标处并从代码中打开?
我需要在表上使用它作为其行的上下文菜单。
答案 0 :(得分:142)
我只是希望通过更多建议来改进letiagoalves很棒的答案 这是一个关于如何向任何html元素添加上下文菜单的演练。
首先,让我们从bootstrap dropdown control添加一个菜单。将它添加到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>
为了保持我们的设计模块化,我们将JavaScript代码添加为名为contextMenu
的jQuery扩展。
当我们致电$.contextMenu
时,我们会传递一个包含2个属性的设置对象:
menuSelector
获取我们之前在HTML中创建的菜单的jQuery选择器。menuSelected
。$("#myTable").contextMenu({
menuSelector: "#contextMenu",
menuSelected: function (invokedOn, selectedMenu) {
// context menu clicked
});
});
基于jQuery boilerplate plugin template,我们会使用Immediately-Invoked Function Expression,因此我们不会混淆全局命名空间。由于我们依赖于jQuery并且需要访问窗口,因此我们将它们作为变量传递给我们,以便我们能够在缩小时继续存在。它看起来像这样:
(function($, window){
$.fn.contextMenu = function(settings) {
return this.each(function() {
// Code Goes Here
}
};
})(jQuery, window);
我们将在调用扩展名的对象上处理contextmenu
鼠标事件。当事件触发时,我们将抓住我们在开头添加的下拉菜单。我们在初始化函数时使用设置传入的选择器字符串来定位它。我们将通过执行以下操作来修改菜单:
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;
});
这将打开打开它的光标右下角的菜单。但是,如果光标位于far right of the screen,则菜单应向左打开。同样,如果光标位于底部,则菜单应打开到顶部。区分包含物理框架的bottom of the window
和代表整个html DOM的document
的底部并且可以远离窗口滚动也很重要。
为实现此目的,我们将使用以下功能设置位置:
我们会这样称呼他们:
.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
}
在我们显示上下文菜单之后,我们需要添加一个事件处理程序来监听它上面的点击事件。我们将删除可能已添加的任何其他绑定,以便我们不会两次触发同一事件。这些可以在菜单打开时随时发生,但由于单击而没有选择任何内容。然后我们可以在click
事件上添加一个新绑定,我们将在下一节中处理逻辑。
作为valepu noted,我们不想在菜单项以外的任何内容上注册点击,因此我们通过将选择器传递到on
函数来设置delegated handler &#34;过滤触发事件的所选元素的后代&#34;。
到目前为止,该函数应该如下所示:
$(settings.menuSelector)
.off('click')
.on( 'click', "a", function (e) {
//CODE IN NEXT SECTION GOES HERE
});
一旦我们知道菜单上发生了点击,我们就会执行以下操作:我们会使用.hide()
隐藏屏幕上的菜单。接下来,我们要保存最初调用菜单的元素以及当前菜单中的选择。最后,我们将使用属性上的.call()
触发传递到扩展中的函数选项,并将事件目标作为参数传递。
$menu.hide();
var $invokedOn = $menu.data("invokedOn");
var $selectedMenu = $(e.target);
settings.menuSelected.call($(this), $invokedOn, $selectedMenu);
最后,与大多数上下文菜单一样,我们希望在用户点击菜单时关闭菜单。为此,我们会监听正文上的任何点击事件,并关闭上下文菜单,如果它是这样打开的话:
$('body').click(function () {
$(settings.menuSelector).hide();
});
注意:Thanks to Sadhir's comment,Firefox linux在右键单击期间触发
document
上的点击事件,因此您必须在body
上设置侦听器。< / p>
扩展名将返回原始对象,该对象引发了上下文菜单和单击的菜单项。你可能必须traverse the dom使用jQuery从事件目标中找到有意义的东西,但这应该提供一个很好的基本功能层。
以下是返回所选项目和操作信息的示例:
$("#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扩展方法中而得到了实质性的更新。如果您想查看我的原创内容,可以查看帖子历史记录,但我相信最终版本会使用更好的编码方法。
加分功能:
如果您想在开发功能时为powerusers或您自己添加一些不错的功能,您可以根据右键单击时保持的任何组合键绕过上下文菜单。例如,如果您希望在按住 Ctrl 时允许显示原始浏览器上下文菜单,则可以将其添加为contextMenu处理程序的第一行:
// return native menu if pressing control
if (e.ctrlKey) return;
答案 1 :(得分:89)
有可能。我为你做了一个工作演示,以便有一个良好的开端。
Working demo (右键点击任何表格行以查看其效果)
首先创建下拉菜单,将其隐藏并将其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;
});
然后当用户选择隐藏下拉菜单/上下文菜单选项时
$contextMenu.on("click", "a", function() {
$contextMenu.hide();
});
答案 2 :(得分:6)
对KyleMit代码添加了一些修改:
传递事件
$("#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");
} });
答案 3 :(得分:-3)
我找到了这个简单而有效的上下文菜单。我正在使用这个库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;
}
},