«前の日記(2013-02-10 (日)) 最新 次の日記(2013-02-14 (木))»  

まちゅダイアリー


2013-02-11 (月)

JQueryでbindの代わりにonを使うとAutoPagerize対応が捗った

ふとJavaScriptが使いたくなったので、tDiaryのページ遷移なしでツッコミを入れるIssueを実装した。コードレビューで @tdtds から将来のjQueryを見越してbind()はon()にしておいた方がいいかもというコメントをもらった。 jQuery の on について調べてみたら、従来の bind() を使う方法よりも AutoPagerize 対応がシンプルにできることがわかったという話 *1

bind() を使った AutoPagerize 対応

イベント処理に bind() を使うときは、対象となる DOM 要素 (ボタンなど) に直接イベントハンドラを結びつける。AutoPagerizeでページが読み込まれたときは、DOMNodeInsertedイベントで検知して追加された要素にもイベントハンドラを結びつけている。

$(function() {
    function comment_ajax(target) {
        // 対象となるDOM要素を選択
        var form = $('form.comment', target);
        form.submit(function(e) {
            e.preventDefault();
            // ここにイベントハンドラを書く
        });
    }

    // AutoPagerize対応。追加で読み込まれたページを対象として同じ処理を適用。
    $(window).bind('AutoPagerize_DOMNodeInserted', function(event) {
        comment_ajax(event.target);
    });

    // does not support IE8 or earlier
    if (window.addEventListener) {
        // AutoPatchWork対応
        // bind()はドットを含むイベント名を認識できない
        window.addEventListener('AutoPatchWork.DOMNodeInserted', function(event) {
            comment_ajax(event.target);
        }, false);
    }

    comment_ajax(document);
});

このように、DOM要素が追加されるたびにイベントハンドラを登録することになる。それにAutoPagerizeとAutoPatchWorkで処理が分かれているのもイマイチ。

bind() の代わりに $(document).on() を使う

jQuery1.7で追加され、今後の標準になるのが on() 関数。これは従来の bind(), delegate(), live() を1つにまとめた関数。詳しくは以下のリンク参照。

jQueryのbind/live/delegateの違いまとめ、と新API .on()の使い方 - y-kawazの日記

jQuery 1.7b1で更に .on/.off という新しいイベントAPIが追加されました。
これは機能的には特に目新しいものはありませんが、これまでに bind/unbind, live/die, delegate/undelegate という6つにも増えてしまったイベントAPIの記述をシンプルに纏めてくれるものです。

on() のうち、従来の live() 相当の書き方を使うことで、AutoPagerize対応がシンプルになった。

$(function() {
    $(document).on('submit', 'form.comment', function(e) {
        // ここにイベントハンドラを書く
        e.preventDefault();
    });
});

AutoPagerizeやAutoPatchWorkのDOMNodeInserted関連の処理がバッサリなくなっている。これでもうまく動くのは、document要素に対してイベントハンドラを登録しているから。従来のbind()関数は直接対象のDOM要素(ここではform.comment)にイベントを登録する。これに対してon()関数ではsubmitイベントが発生したあとに、on()関数内でイベント発生元の要素 (form.comment) を特定するという仕組みになっている。イベント発生後に要素を特定するので、DOM要素の追加/削除の影響を受けないということ。なるほどねぇ。

最も、常に $(document).on() を使えばいい訳ではなく、用途によって使い分けるのが大切。それでも前述のリンクによれば、bind()より$(document).on() (従来のlive())のほうが速いらしい。

ということで、他の tDiary プラグインでも AutoPagerize 対応の部分を書き直していこう。

*1 僕の知識が jQuery1.2 時代のままだったことが問題であって、 jQurey1.3 以降の live() でも実現できる。