web-dev-qa-db-ja.com

コンテキストメニューとしてBootstrap 3ドロップダウンメニューを使用します

Bootstrap 3を使用して、ドロップダウンメニューをカーソルに置き、コードから開くにはどうすればよいですか?

テーブルの行のコンテキストメニューとして使用する必要があります。

69
MojoDK

可能です。良いスタートを切るためのデモを作成しました。

ワーキングデモ(テーブルの行を右クリックして動作を確認)

まずドロップダウンメニューを作成し、非表示にしてそのpositionabsoluteに変更します:

#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();
});
90
letiagoalves

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>

拡張設定:

設計をモジュール化するために、contextMenuというjQuery拡張機能としてJavaScriptコードを追加します。

$.contextMenuを呼び出すとき、2つのプロパティを持つ設定オブジェクトを渡します。

  1. menuSelectorは、以前にHTMLで作成したメニューのjQueryセレクターを取ります。
  2. コンテキストメニューアクションがクリックされると、menuSelectedが呼び出されます。
$("#myTable").contextMenu({
    menuSelector: "#contextMenu",
    menuSelected: function (invokedOn, selectedMenu) {
        // context menu clicked
    });
});

プラグインテンプレート:

jQueryボイラープレートプラグインテンプレート に基づいて、 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()。を使用して要素を配置します。
    • positionabsoluteに設定されていることを確認する必要があります。
    • 次に、イベントの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の下部 と、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
}

メニュー要素のクリックイベントのバインド:

コンテキストメニューを表示した後、イベントハンドラーを追加してクリックイベントをリッスンする必要があります。同じイベントが2回発生しないように、既に追加されている可能性のある他のバインディングを削除します。これらはメニューを開いたときにいつでも発生しますが、クリックしてオフになっているため何も選択されていません。その後、次のセクションでロジックを処理する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は右クリック中に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拡張メソッドでラップすることにより大幅に更新されました。私のオリジナルを見たいなら、あなたは投稿履歴を見ることができますが、この最終バージョンははるかに優れたコーディング慣行を利用していると思います。

ボーナス機能

パワーユーザーや自分で機能を開発するために素敵な機能を追加したい場合は、右クリックしたときに保持されているキーの組み合わせに基づいてコンテキストメニューをバイパスできます。たとえば、元のブラウザのコンテキストメニューを押したときに表示できるようにする場合 Ctrl、これをcontextMenuハンドラーの最初の行として追加できます。

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

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/

6
Far Dmitry