2016-04-05 14 views
7

どこかをクリックしてトリガされたワンタイムイベントを作成したいとします。このイベントは、ボタンをクリックすると作成されます。ボタンをクリックしたときにイベントがトリガーされることはなく、その後の任意のクリック(ボタンを含む)だけが発生します。setTimeoutとイベントの伝播

だから私は、次のような一部のHTML持っていると言う:私はイベントの伝播を停止しないようにしたい

$('#btn').click(function() { 
    $(document).one('click', function() { 
    console.log('triggered'); 
    }); 
}); 

$('#someparent').click(function() { 
    // this must always be triggered 
}); 

が、上記で:

<body> 
    <div id="someparent"> 
    <div id="btn"></div> 
    </div> 
</body> 

そして、次のJavaScript(jqueryのを)たとえば、イベントはドキュメントにバインドされ、イベントがバブルアップし、イベントがトリガされます。この問題を解決するために

一つの方法は、タイムアウトでイベント作成をラップするように思わ:

$('#btn').click(function() { 
    setTimeout(function() { 
    $(document).one('click', function() { 
     console.log('triggered'); 
    }); 
    }, 1); 
}); 

$('#someparent').click(function() { 
    // this must always be triggered 
}); 

、これは正常に動作しますが、私は、これは安全であるかどうかと思いまして。実行命令のいくつかの概念は、これが常に機能することを保証しているのですか、それとも偶然に作用していますか?他のソリューション(別のネストされた.one()イベント)があることはわかっていますが、特にsetTimeoutとイベントの伝播がどのように相互運用するかの答えを探しています。

以下のフィドルは、2つのdivを示しています。最初のものは間違った動作をします(ドキュメントイベントがすぐにトリガされます)。第二のdivをクリックして、ドキュメントの任意の場所(白い部分)に希望の挙動を示しています

https://jsfiddle.net/Lwocuuf8/7/

+0

あなたはクリックイベントを配線し、イベントをしたら、単純にハンドルを削除することはできません(ソースがボタンでない限り)トリガーされましたか? –

+0

あなたは何を意味するのか分かりませんか? – jkgeyti

+0

は、バブリングを防ぐためにfalseを返すだけです。 – TecHunter

答えて

7

イベントバブリングイベントは、可能な限り深い要素にトリガした後、それがその後のネストに両親にトリガ、ということを意味注文。

から:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Adding_messagesウェブブラウザでメッセージ

追加

、メッセージは、イベントが発生し、そこ それに取り付けられたイベントリスナである任意の時間に添加されます。リスナーがない場合、 イベントは失われます。したがって、クリックイベントハンドラ を持つ要素をクリックすると、他のイベントと同様にメッセージが追加されます。

setTimeoutを呼び出すと、 が2番目の引数として渡された後にキューにメッセージが追加されます。キューに他のメッセージがない場合、 メッセージはすぐに処理されます。しかし、メッセージがある場合、 は、他のメッセージが処理されるのを待つ必要があります。 このため、2番目の引数は、保証時間ではなく、 の最小値を示します。

だから、あなたが持っている行動は、偶然ではない、あなたは、キュー内のメッセージは、あなたがタイムアウト後に追加したメッセージを処理する前に処理されることが保証されています。

+1

私が探していたものです。これにより、期待される動作が保証されます。ありがとうございました。 – jkgeyti

2

"アクティベーション"ボタンをクリックした後、次のページ上の任意の場所(アクティベーションボタンを含む)をクリックすると特別なイベントが発生します。これは、簡単にフラグを使用して処理されます。

var activationFlag = false; 

$('#btn').click(function(event){ 
    event.preventDefault(); 

    if(!activationFlag) { 
    event.stopPropagation(); 
    console.log('Global event activated'); 
    } 

    activationFlag = true; 
}); 

$('#someparent').click(function(event){ 
    if(activationFlag) { 
    console.log('Time for a special event'); 
    } else { 
    event.preventDefault(); 
    event.stopPropagation(); 
    } 
}); 
+1

ありがとうございます。それは実世界の問題から構築された故意の例なので、少し奇妙に見えます。私が使った 'setTimeout'アプローチよりも優れた解決策が数多くありますが、期待された動作が保証されているかどうかの答えを具体的に探していました。しかし、この例ではフラグが適切な解決策であることに同意しますが、例のようにイベントの伝播を止めないでください。 – jkgeyti

2

Here is a workaround代わりに2番目のイベントのフラグを使用して:

var documentWaitingClick = false; 
$(function() { 
    $(document).on('click', function(e) { 
    if (documentWaitingClick) { 
     //simulate the "one" 
     documentWaitingClick = false; 
     console.log('document click'); 
    } else if (e.target.tagName === 'BUTTON') { 
     documentWaitingClick = true; 
     console.log('button click') 
    } 
    }); 
});