jQuery1.4aでのlive event/special event
BPStudy#28 : ATNDの発表資料。
スライドなどは用意しておらず、これで発表する。
自己紹介
技術方面でのキーワード
今日の本題jQuery1.4
先日jQuery1.4のアルファ版がリリースされた。
jQuery 1.4 Alpha 1 Released | Official jQuery Blog
- live eventの改良
以下話さないので原文ママ
- append, prepend, etc. have been heavily optimized.
- add has been adjusted to always return elements in document order.
- find, empty, remove, addClass, removeClass, hasClass, attr, and css have been heavily optimized.
今回はlive eventの改良と、リリースノートには載っていない
special eventの改良について話します。
live event
使い方
通常のevent貼り剥がしの場合
// 貼付ける $(selecter).bind(eventType,function(ev){}); // 剥がす $(selecter).unbind(eventType);
こうすると、今、$(selecter)で選択された要素に対して、
eventType(click等)のevent handlerとして、
第2引数の関数を設定したり、解除したり出来る。
live eventの場合はbind/unbindがlive/dieになる。
// 貼付ける $(selecter).live(eventType,function(ev){}); // 剥がす $(selecter).die(eventType);
使い道
- 動的に追加削除するコンポーネント群へeventを設定
- ショッピングカートとか
- autopagerizeつかってるページとか
はてブでこれを実行して2ページ目を追加表示した後、
2ページ目の中のリンクをクリックしてもalertが出る。
jQuery('a').live('click',function(){ alert('hoge'); return false; });
- 大量の要素にeventを設定
- パフォーマンスが文字通り桁違い
console.time('select'); jQuery('a'); //1305件くらいある画面での実行例 console.timeEnd('select'); // 5〜10ms var f = function(){}; console.time('bind'); jQuery('a').bind('click',f); console.timeEnd('bind'); // 初回実行時1500ms程度 // 2回目以降実行時200ms程度 jQuery('a').unbind('a'); console.time('live'); jQuery('a').live('click',f); console.timeEnd('live'); // 5〜10ms void 0;
- DOMContentLoadedを待たずにeventを設定
- デモ
- Firebug等のconsoleを開いた状態で試せる
- click eventをlive eventとしてa要素に設定
- bodyの最後の方で意味もなく読み込みが重いJavaScriptをたくさん読み込んで、DOMContentLoadedを遅延させている
- DOMContentLoadedにclick eventを設定できているのがわかる
- デモ
live eventの1.4での強化
サポートしているeventTypeの追加
submit,change,mouseenter,mouseleave,focus,blur
contextのサポート
このような書き方で、context配下に限定して、
cssSelectorに合致する要素にeventを貼る事ができるようになった。
jQuery(cssSelector,context).live(eventType,function(ev){});
このコードは.main配下のaタグ全てがclickでalertを出すようにするが、
1.3.2では使えない。
jQuery('a','.main').live('click',function(){ alert('hoge'); return false; });
一つのCSSセレクタにしてしまえば1.3.2でも同じ事が再現出来る。
jQuery('.main a').live('click',function(){ alert('hoge'); return false; });
例えばCSSセレクタではできない or したくないような
ある程度複雑な絞り込みをした後、
それぞれの配下についてlive eventを貼りたいような場合は、
contextのサポートがないと実現出来ない。
(function($){ $('.main ul').filter(function(i){ return !((i + 1) % 5); }).each(function(i,n){ console.info(n); $('a',n).live('click',function(ev){ alert('hoge'); return false; }) }); })(jQuery);
dataのサポート
第2引数にobjectを渡すとeventオブジェクトのdataプロパティから参照出来るようになった。
いまひとつ有効な使いどころが思いつかない。
var data = {message:'hello'}; jQuery('a').live('click',data,function(ev){ alert(ev.data.message); return false; });
special event
custom eventを定義するための簡易フレームワークのようなもの。
custom eventについては、この辺を参照
使い方
jQuery.event.special.eventType = { setup:function(){},teardown:function(){}};
このような、setup,teardownをキーに関数を値に持つオブジェクトを渡してやればよい。
special eventの歴史
- 1.2.2で導入
- 1.3 specialAll導入
- 1.4a specialAllのspecialへの一本化
1.2.2で導入されたspecial event
l2137-l2157
mouseenter: { setup: function() { if ( jQuery.browser.msie ) return false; jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler); return true; }, teardown: function() { if ( jQuery.browser.msie ) return false; jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler); return true; }, handler: function(event) { // If we actually just moused on to a sub-element, ignore it if ( withinElement(event, this) ) return true; // Execute the right handlers by setting the event type to mouseenter arguments[0].type = "mouseenter"; return jQuery.event.handle.apply(this, arguments); } },
IE以外のブラウザでのmouseover eventに相当するがIEだとmouseenterで、
このコードではIE以外でもmouseenterを使えるようにし、
mouseenterをクロスブラウザ対応させている。
mouseout/mouseleaveについても同様の事をやる事で、
hoverメソッドをシンプルに実装出来るようにしている。
l2233-l2235
hover: function(fnOver, fnOut) { return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut); },
このspecial event1要素×1eventTypeにつき1回のみbindすることができる。
1.3でのspecialAllの導入
jQuery1.3でのspecialAllの唯一の使用箇所がlive eventを定義している箇所である。
jQuery1.3.2 l2777-l2796
specialAll: { live: { setup: function( selector, namespaces ){ jQuery.event.add( this, namespaces[0], liveHandler ); }, teardown: function( namespaces ){ if ( namespaces.length ) { var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)"); jQuery.each( (jQuery.data(this, "events").live || {}), function(){ if ( name.test(this.type) ) remove++; }); if ( remove < 1 ) jQuery.event.remove( this, namespaces[0], liveHandler ); } } } }
使い方は↓で、special eventととても似ているが
jQuery.event.specialAll.eventType = { setup:function(){},teardown:function(){}};
- special eventのsetup
- 1要素×1eventTypeにつき1回のみ実行される
- 正確にはbindされていない状態での最初のbindのみ。
- bind→unbind→bindなら2回実行される
- そのevenTypeのeventを実際にbindする
- 1要素×1eventTypeにつき1回のみ実行される
- specialAll
- 1要素×1eventTypeでも何度でも実行される
- そのevenTypeのeventを実際にbindしない
1.4aでのspecialAllのspecialへの一本化
specialAllのsetup,teardownの上位互換機能として、
specialのadd,removeが使えるようになった。
live eventの定義もspecialのadd,removeにより実現されるようになった。
また、specialAllはlive eventの定義専用という感が強かったが、
specialに統合され、specialのsetup,teardownと併用できるようになったことで、
できることも増えた。
add自体の機能もspecialAllのsetupより強化され、
addの戻り値が関数の時、それをevent handlerとして実際に貼付ける
といった事ができるようになった。
それによってbind時にoptionを渡して、振る舞いを換えるといったことが可能になった。
multiclick event
multiclick event demo
$('#example') // 3click .bind('multiclick', { threshold: 3 }, function( event ) { alert('Clicked three times!'); }) // 5click .bind('multiclick', { threshold: 5 }, function( event ) { alert('Clicked 5 times!'); });