古いコードを含むJavaScriptツールに取り組んでいるので、ツール全体を書き直すことはできません。
現在、メニューは下部に固定された位置に追加され、クライアントは、ユーザーがメニューの外側から何かを開始するときに自動的に閉じる必要があることを除いて、メニューを開閉するトグルボタンを持っていることを非常に好みますたとえば、ユーザーがページに戻って、何かを選択したり、フォームフィールドをクリックしたりします。
これは、click
のbody
イベントで技術的に機能し、クリックでトリガーされますが、古いコードには多数のアイテムがあり、クリックイベントは内部リンクで処理され、return false
は、サイトがリンクのhref
タグに進まないようにするために、クリック機能に追加されました。
したがって、明らかに、このような一般的な関数は機能しますが、falseを返すと伝播が停止する内部リンクをクリックした場合は機能しません。
$('body').click(function(){
console.log('clicked');
});
とにかくボディクリックイベントを強制する方法はありますか、またはグローバルなクリックイベントなどを使用してメニューを非表示にする方法はありますか?
何年も前に作成されたアプリケーションの他のすべてのクリックを書き換える必要はありません。特に、falseを返さずにそれらを書き換える手がかりがないため、それはモンスタータスクになりますが、href
に移動させないでください。
最新のDOM実装のイベントには、capturingとbubblingの2つのフェーズがあります。キャプチャフェーズは、ドキュメントのdefaultView
からイベントターゲットに流れる最初のフェーズです。次に、イベントターゲットからdefaultView
に戻るバブリングフェーズが続きます。詳細については、 http://www.w3.org/TR/DOM-Level-3-Events/#event-flow を参照してください。
イベントのキャプチャ段階を処理するには、addEventListener
の3番目の引数をtrue
に設定する必要があります。
document.body.addEventListener('click', fn, true);
悲しいことに、ウェスリーが述べたように、イベントのキャプチャフェーズは、古いブラウザでは確実に処理できないか、まったく処理できません。
考えられる解決策の1つは、クリックのイベント順序が次のようになるため、代わりにmouseup
イベントを処理することです。
mouseup
イベントをキャンセルするハンドラーがないことが確実な場合は、これが1つの方法(そしておそらく間違いなくより良い方法)です。もう1つ注意すべきことは、ほとんどではないにしても(すべてではないにしても)多くのUIメニューがマウスを押すと消えることです。
Andy Eと協力して、これは力の暗い側面です:
_var _old = jQuery.Event.prototype.stopPropagation;
jQuery.Event.prototype.stopPropagation = function() {
this.target.nodeName !== 'SPAN' && _old.apply( this, arguments );
};
_
例: http://jsfiddle.net/M4teA/2/
すべてのイベントがjQueryを介してバインドされている場合は、ここでそれらのケースを処理できることに注意してください。この例では、_<span>
_を扱っていない場合、元の.stopPropagation()
を呼び出すだけです。
防ぐことはできません、いいえ。
できることは、これらのイベントハンドラをコード内で手動で書き換えることです。これはトリッキーなビジネスですが、保存されたハンドラーメソッドにアクセスする方法を知っている場合は、回避することができます。私はそれを少し遊んでみましたが、これは私の結果です:
_$( document.body ).click(function() {
alert('Hi I am bound to the body!');
});
$( '#bar' ).click(function(e) {
alert('I am the span and I do prevent propagation');
e.stopPropagation();
});
$( '#yay' ).click(function() {
$('span').each(function(i, elem) {
var events = jQuery._data(elem).events,
oldHandler = [ ],
$elem = $( elem );
if( 'click' in events ) {
[].forEach.call( events.click, function( click ) {
oldHandler.Push( click.handler );
});
$elem.off( 'click' );
}
if( oldHandler.length ) {
oldHandler.forEach(function( handler ) {
$elem.bind( 'click', (function( h ) {
return function() {
h.apply( this, [{stopPropagation: $.noop}] );
};
}( handler )));
});
}
});
this.disabled = 1;
return false;
});
_
上記のコードはjQuery 1.7でのみ機能することに注意してください。これらのクリックイベントが以前のjQueryバージョンまたは「インライン」にバインドされている場合、コードを使用できますが、「古いハンドラー」に別の方法でアクセスする必要があります。
ここでは、たとえば、これらのハンドルがfalse
を返すのではなく、明示的に.stopPropagation()
を呼び出すという「完璧な世界」のシナリオを想定していることを知っています。だから、それはまだ役に立たないアカデミックな例かもしれませんが、私はそれを出すように感じました:-)
edit:ちょっと、_return false;
_はうまく動作します。イベントオブジェクトは同じ方法でアクセスされます。
これがfirstイベントハンドラーの動作であることを確認すると、次のようなことができます。
$('*').click(function(event) {
if (this === event.target) { // only fire this handler on the original element
alert('clicked');
}
});
ページに多くの要素がある場合、これは非常に遅くなり、動的に追加されたものに対しては機能しないことに注意してください。
本当にやりたいことは、イベントのキャプチャフェーズのイベントハンドラーをバインドすることです。ただし、これはIEでは私の知る限りサポートされていません。そのため、それほど便利ではないかもしれません。
http://www.quirksmode.org/js/events_order.html
関連する質問:
this
はキーです(vs evt.target)。例を参照してください。
document.body.addEventListener("click", function (evt) {
console.dir(this);
//note evt.target can be a nested element, not the body element, resulting in misfires
console.log(evt.target);
alert("body clicked");
});
<h4>This is a heading.</h4>
<p>this is a paragraph.</p>
JQueryを使用して、ドキュメントDOMにイベントリスナーを追加できます。
$(document).on("click", function () {
console.log('clicked');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
私はこれがあなたが必要なものだと思う:
$("body").trigger("click");
これにより、どこからでもボディクリックイベントをトリガーできます。