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

时间:2013-09-06 21:06:22

标签: jquery twitter-bootstrap twitter-bootstrap-3

使用Bootstrap 3,如何将下拉菜单放在光标处并从代码中打开?

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

4 个答案:

答案 0 :(得分:142)

我只是希望通过更多建议来改进letiagoalves很棒的答案 这是一个关于如何向任何html元素添加上下文菜单的演练。

Let's start off with a working demo in jsFiddle

标记:

首先,让我们从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个属性的设置对象:

  1. menuSelector获取我们之前在HTML中创建的菜单的jQuery选择器。
  2. 单击上下文菜单操作时将调用
  3. menuSelected
  4. $("#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
      • 然后,我们会使用事件的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;
    });
    

    修复菜单边缘案例:

    这将打开打开它的光标右下角的菜单。但是,如果光标位于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);
        }
    });
    

    截图:

    Context Menu Screenshot

    更新注意:

    这个答案已经通过将其包装在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代码添加了一些修改:

  • 移动&#34;在文档点击&#34;来自&#34; foreach&#34;
  • 的处理程序
  • 删除&#34; foreach&#34;,只需将事件添加到选择器
  • 隐藏菜单&#34;文档上下文菜单&#34;
  • 传递事件

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

答案 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;
        }
        },