JQueryでイベントブロッキング
前回の jQueryで一回だけイベント - なんたらノート 第二期 でちょっとツメが甘かったので、もうちょっと具体的に言うと、ということで、イベントブロッキングを考えます。
たとえば、ユーザのクリックによって、アニメーションエフェクトが起こったとき、同じものをもう一度クリックできたりすると、イベントが二重に発生して、エフェクトがちょっと不恰好になることがあります。アニメーション効果が完了するまで、イベントをブロックしておいて、演出が終わったら再度クリックできるようになる、というのを作ってみましょう。
function showinfobox() { var q = $(this); q.unbind('click', showinfobox); $('#infobox').show(function() { q.click(showinfobox); }); return false; } $('#clickme').click(showinfobox);
あまりスマートじゃないですね。関数が使われ方、つまり「何にアサインされるか」、を意識しすぎです。
どのように使われるかが固定されるていて、それが1回しか使われないようなものは、名前を持った再利用可能な「関数定義」である必要はありません。というか、むしろ再利用できないほうがいいです。
これを関数リテラルにできるでしょうか。
$('#clickme').click(function() { var q = $(this); var f = ... //関数自身へのポインタが欲しいけど、この関数には名前がないから参照できない!? q.unbind('click', f); $('#infobox').show(function() { q.click(f); }); return false; });
関数を指す変数がないと、ブロックのためのunbindも、再開のための再bindもできませんね。例の、カレント呼び出しコンテキストのthisみたいな感じで、「この関数」を指す変数がないか... あります。Javascriptの予約語、argumentsに入っています。
$('#clickme').click(function() { var q = $(this); var f = arguments.callee; q.unbind('click', f); $('#infobox').show(function() { q.click(f); }); return false; });
うん、実用的。さらに、このクリックイベントの中が条件付きになる予定が全くないなら、もっと短く、こうなります。
$('#clickme').one('click', function() { var q = $(this); var f = arguments.callee; $('#infobox').show(function() { q.one('click', f); }); return false; });