Используйте раскрывающееся меню Bootstrap 3 в качестве контекстного меню

Используя Bootstrap 3, как я могу поместить раскрывающееся меню в курсор и открыть его из кода?

Мне нужно использовать его в таблице в качестве контекстного меню для его строк.

Ответ 1

Это возможно. Я сделал вам рабочую демонстрацию, чтобы хорошо начать.

Рабочая демонстрация (щелкните правой кнопкой мыши по любой строке таблицы, чтобы увидеть ее в действии)

Сначала создайте раскрывающееся меню, спрячьте его и измените его 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;
});

Затем, когда пользователь выбирает опцию hide dropdown/context menu:

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

Ответ 2

Я просто хотел улучшить letiagoalves отличный ответ с еще несколькими предложениями.
Здесь вы найдете пошаговое руководство о том, как добавить контекстное меню к любому элементу 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>

Настройки расширения:

Чтобы сохранить модульный дизайн, мы добавим наш код JavaScript как расширение jQuery под названием contextMenu.

Когда мы вызываем $.contextMenu, мы передадим объект настроек с двумя свойствами:

  • menuSelector принимает селектор jQuery меню, которое мы создали ранее в HTML.
  • menuSelected будет вызываться при нажатии на действие контекстного меню.
$("#myTable").contextMenu({
    menuSelector: "#contextMenu",
    menuSelected: function (invokedOn, selectedMenu) {
        // context menu clicked
    });
});

Шаблон плагина:

Основываясь на шаблоне плагина jQuery шаблона, мы будем использовать Immediately-Вызываемое выражение функции, чтобы мы не путали глобальное пространство имен. Поскольку у нас есть зависимости от 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;
});

Исправление граничных условий меню:

Это откроет меню в нижней правой части курсора, который открыл его. Однако, если курсор находится в правее экрана, меню должно открываться влево. Аналогично, если курсор находится внизу, меню должно открываться вверху. Также важно различать нижнюю часть window, которая содержит физический фрейм, а нижняя часть document, которая представляет весь html DOM, и может прокрутите далеко мимо окна.

Для этого мы установим местоположение, используя следующие функции:

Мы будем называть их следующим образом:

.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 отметил, мы не хотим регистрировать клики на чем-либо кроме элементов меню, поэтому мы настраиваем делегированный обработчик, передав селектор в функцию on, которая будет "фильтровать потомки выбранных элементов, которые запускают событие".

Пока функция должна выглядеть так:

$(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();
});

Примечание: Благодаря комментарию Sadhir, Firefox linux запускает событие click на document во время правого щелчка, поэтому вам нужно настройте слушателя на body.

Пример Синтаксис:

Расширение вернется с исходным объектом, который поднял контекстное меню и элемент меню, который был нажат. Возможно, вам придется пересечь 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;

Ответ 3

Добавлены некоторые изменения в KyleMit код:

  • перемещен обработчик "нажимать документ" из "foreach"
  • удалено "foreach", просто добавьте событие в селектор
  • скрыть меню в контекстном меню документа
  • передача событий

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

Ответ 4

Я нашел это простое и рабочее контекстное меню. Я использую эту библиотеку 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>

ContextMenu:

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