Javascriptコンテキストメニュー:小さいながらも強力

おそらく、jQueryやプロトタイプなどの一般的なライブラリに基づいたコンテキストメニューのjavascript実装を複数回目にしました。 そのため、APIの不便さ、多くのコード、リソース要件、膨大な量のhtmlコードを生成することが好きなことなど、必然的に主な欠点に直面していました。 ある時点で、これらの問題は私の怠inessを圧倒し、次のタスクを設定することでそれらと戦うことにしました。

コンテキストメニュー

UPD :プロジェクトをGoogleコードで投稿、使用、開発:
svn checkout js-cmenu.googlecode.com/svn/trunk js-cmenu-read-only


機能的


サブメニューがあります。 ネストは理論的には無制限です。
メニュー項目はアクセス不可(無効= true)、非表示(visible = false)にすることができ、キャプション、アイコンを動的に変更し、新しいメニュー項目とサブメニューを追加できます。
画面領域のさまざまな境界で正しく動作します。メニューがスクロール可能なdiv(メニューを呼び出した要素でスクロールする)にある場合、状況は解決されます。
ラジオメニュー:メニュー項目のいずれかを選択します。
ビルドおよびさらにメニューの動作のためのいくつかのオプション。

必要性がないため、次の機能が削除されました:ajax-requestによるメニューの作成、右クリック(どこでも機能しません)、水平メニュー(めったに使用されませんでした)。

仕組み


すべてのメニューが収集されるグローバルコレクション(線形リスト)があります。 メニュー自体は、メニュー項目だけでなく、その動作と状態に関する情報を含む特定のオブジェクトです。 メニュー項目にはサブメニューが含まれる場合があります。

ページにメニューを表示するには、ページの任意の要素(通常は画像またはリンクを使用します)をポイントする必要があります。また、クリック(イベント)がクリックと異なる場合にメニューが呼び出されるこの要素のイベントを示す必要があります。

1つのメニューをページ上の多くの要素に追加できます。 このメニューからは乗算されませんが、どこから呼び出されたかがわかります(これは基本的にハンドラー内にあります)。

新しい関数を追加し、不要なものを削除するのが難しくないように、コードをできるだけシンプルで簡単なものにしようとしました。 たとえば、ラジオメニューの実装には、5行または6行と10分の時間が必要でした。 必要に応じてコードを変更しますが、それでもコメント内の著者のリンクを示します。

サンプルを作成して呼び出す


メニューは、目的のメニューの倒錯度に応じて、さまざまな方法で作成できます。 最も簡単なことは、一連のアクションをメニューデザイナーに渡すことです。
var x = $.cmenu.getMenu([
new menuItem('', 'arrow_left',function(){history.back();}),
new menuItem('!', 'arrow_right',function(){history.forward();}),
new menuItem('','arrow_refresh',function(){location.href=location.href;})
]);
$('.callMenu').bindMenu(x);
$('#main_link').bindMenu(x);

出口で、完成したメニューへのリンクを取得します。 どこにでもバインドできます。 すでに禁止されています! いいえ、嘘をついています。 さらにシンプルにすることができます:アクションの配列を要素にバインドします。
$('.callMenu').bindMenu([
new menuItem('', 'arrow_left',function(){history.back();}),
new menuItem('!', 'arrow_right',function(){history.forward();}),
new menuItem('','arrow_refresh',function(){location.href=location.href;})
]);

私は完全に忘れてしまった、それはさらに簡単にすることができます:アクションの代わりにこれらのアクションのパラメータの配列を設定します。
$('.callMenu').bindMenu([
['', 'arrow_left',function(){history.back();}],
['!', 'arrow_right',function(){history.forward();}],
['','arrow_refresh',function(){location.href=location.href;}]
]);

これは、アクションコンストラクターを呼び出すことと同じです。
menuItem = function(caption,icon,execute,submenu)

または単にjson経由でアクションを設定する
{
caption:'Caption',
icon:' undefined, , ',
visible:true,
disabled:false,
execute:function(){},
submenu:{-, , — }
}

これは、タスクの大部分をカバーします。 しかし、外部要因に応じて動的に変化するメニューが必要な場合はどうでしょうか? 私はこれについて多くのことを考え、さまざまな実装を試みました。その結果、解決されました。関数をメニューデザイナーに渡します。 この関数は、メニューを表示する必要があるたびに呼び出されます。
注意:重要です!
メニュー全体を最適化するために、この機能はかなり奇妙に機能します。 彼女は唯一のパラメーターとして、完全に自由に使えるメニューオブジェクトを受け取ります。 嘘(これはメニューの再描画を必要としないことを意味します)、真実、または一連のアクションのいずれかを返します。 しかし、アクションの配列を返すことはできませんが、単にメニューオブジェクトの「a」メンバーに書き込むだけです-menu.a = [アクションの配列]、これは同等です。
多くの場合、メニューは環境の状態だけでなく、どのメニュー項目が呼び出されたかにも依存します。 このメニューにはメンバーの呼び出し元がいます。 メニューを呼び出したDOM要素へのリンクが含まれています。 サブメニューの場合、この要素は親メニューのhome要素へのリンクになるため、親メニューへのリンクを含むparentMenuメンバーを見るのが理にかなっています。

典型的な機能は次のようになります。
  menuGenerator = function(メニュー){
	 if(!menu.a){
		 //メニューを初期化します
		 trueを返します。  //再描画が必要
	 }
	 if(myVarChanged()){//オブジェクトモデルで何かが起こった
		 menu.a.doAction.disabled = myVarValue();
		 trueを返します。  //再描画が必要
	 }
	 if(menu.caller.id = 666){
		 menu.a.doAction.visibe = false;
		 trueを返します。  //再描画が必要
	 }
	 falseを返します。  //すべてがまだ再描画されている必要はありません
 } 


オブジェクトアクションについてのいくつかの言葉。 その中で最も重要なメソッドは実行です。 このメソッドは、メニュー項目をクリックすると呼び出されます。 3つのパラメーターが必要です。 1つ目はアクションオブジェクト自体、2つ目はメニュー、3つ目はメニュー呼び出しの配列チェーンです(複雑なマルチレベルメニューに役立ちます)。
アクションオブジェクトの重要度の低いメンバーはサブメニューです。 アクションの配列、またはメニュージェネレーター関数があります。

メニューのラジオ動作については、メニューオブジェクトでmenu.type = 'radio'プロパティを設定し、2つのメソッド:set(str)およびget

例を見てください。ラジオメニューのトピックがそこに表示されます。

そして最後の1つ。 バインドの代わりに、より複雑な構造を使用できます。 これにより、存在しない要素のイベントの形で家の中のゴミが回避されます。 はい、インラインコールについて話しています。 factory-menuクラスには、次のようなパラメーターから1行を返す$ .cmenu.getCaller(メニュー)または$ .cmenu.getCaller(イベント、メニュー)メソッドがあります。
onclick="$.cmenu.show(0,this);$.cmenu.lockHiding=true;" onmouseout="$.cmenu.lockHiding=false;"
この行はアイテムに添付できます。

実装をよく知っているなら、隠さないでください-声を出してください。

Source: https://habr.com/ru/post/J43111/


All Articles