読者です 読者をやめる 読者になる 読者になる

DOM Ready前にイベントを設定する方法(jQuery.liveの紹介)

健康診断で身長伸びてました。agoです。

今開発中のサイトで$().liveを中心にした実装を行っているので簡単にまとめてみました。

$().liveって?

jQuery 1.3系からサポートされた、イベントハンドラの設定用methodです。

$().bindとどこが違うの?

$().bindは指定されたhtml elementsに対して直接ブラウザの機能を使ってイベントを設定しますが、$(selector).liveは一旦document objectでイベントをキャッチした後、jQueryが発生元の要素とselectorをつきあわせて一致した場合イベントハンドラを呼び出します。

何がいいの?

以下のような利点があります。

  1. DOM Readyを待たずにイベントを設定できる。
    通常jQueryでは$(function () {});(DOM Ready)内で初期化を行いますが、htmlの量が多かったり、サーバからのレスポンスが遅延した場合、「画面上は表示されてるけど、DOM Readyが呼ばれていない」時間が発生します。
    $().liveであればdocument objectさえ存在すればイベントの設定が出来るため、イベントハンドラの取りこぼしがなくなります。
  2. DOM構築後に追加された要素でもイベントを発生できる。
    通常、一旦DOM構築後に追加された要素は構築前に設定されたイベントは発生しませんが、$().liveの場合document object自体にイベントが設定されているので、$().live実行時に存在しない要素(初期化後に$().append()で追加した要素など)に対してもイベントを設定できます。
  3. 対象要素が多くても設定されるハンドラの数が増えない。
    普通にイベントを設定した場合、100個の要素に対しては100個のイベントを設定するため要素数に比例して処理速度が遅くなりますが、$().liveであれば一つのイベントハンドラで100個の要素をまかなうことも可能なため要素数と処理速度は比例しません。

問題点は?

若干追い切れていない部分もありますが、以下のような問題が発生する場合があります。

  1. Traversing methodを併用すると意図しない要素で呼ばれる場合がある。
    DOM構築前に$(selector1).find(selector2).liveといった呼び出し方をした場合、意図しない要素でイベントが呼ばれる場合があるようです。
    今のところ$(selector1 + ' ' + selector2).liveといった形式であれば問題は発生していないため、$().liveとTraversing methodの併用は避けた方が無難なようです。
    (1.4.2から追加された$().delegate()を使用する方法もあるかもしれません)
  2. event.preventDefault()で止まらない場合がある。
    $().live(function (event) { event.preventDefault(); });でイベントの伝播が止まらない場合があります。
    return false;なら停止できるため、確実にイベントの伝播を停止したい場合return false;を使いましょう。
  3. FireQueryでイベントが見えない。
    通常のイベント設定の場合、FireQueryを使用することにより各elementsに設定されたイベントをFirebugのhtml tabで確認することが出来ますが、$().liveで設定されたイベントはdocument objectに設定されるためFireQueryで確認することが出来ません。
  4. イベント発生時にDOMが構築されていることが保証されない。
    イベントが発生した時点でDOMの構築が完了していない可能性があるため、イベントハンドラ内でDOMアクセスを行うと問題が発生する可能性があります。
    これに関してはイベントハンドラ内で以下のような処理をかませることで回避できます。
    $('a').live('click', function () {
        var self = this;
        $(function () {
            $(self).hoge();
            //  DOM access
        });
        return false;
    });

実際使うには?

<head>内に<script>を記述し、イベントハンドラ部分を$(function () {});の外部に置いて$().liveに書き換えましょう。
複雑な処理がない場合、簡単な置き換えで対応出来る場合もあります。

2010/06/16 追記 当初「$.liveはjQuery 1.4系から追加された」と書いていましたが、「1.3系から追加」に修正しました。

カヤックでは成長する技術者を募集しています!