jQuery Mobileのナビゲーション機能

jQuery Mobileにおける「ページ」は data-role 属性に “page” を指定された要素(通常は div 要素)により構築されます。通常はその中に “header” , “content” , “footer” などの役割を持った div 要素が含まれ、それぞれが更に一般的なHTMLやフォーム、jQuery Mobile ウィジェットなどを包含します。

ページ読み込みの基本的な流れは、次のようになります。まず、最初のページは通常のHTTPリクエストで表示されます。そして以降のページは、要求された内容を現在のページのDOMに挿入してやることで表示されます。これによって複数のページが同時にロードされ data-url 属性により再訪を容易にします。

URLが最初にリクエストされた時、そこには1つ以上の「ページ」が含まれることになりますが、その最初のひとつだけが表示されます。同時に複数のページを読み込ませることは、単一のページよりもプリフェッチが出来ることでスムーズな表示が可能になります。

Ajaxによるページ・ナビゲーション

jQuery Mobileでのナビゲーションは location.hash の更新に基づいて行われます。ページの遷移が行われた場合、現在のページから次のページへの滑らかな切り替えが、遷移先のページが既に読み込まれているか、あるいはAjaxにより自動的に読み込まれるかの別とは関係なく行われます。

ハッシュは、最初に読み込まれた実際のURLを基点にjQuery Mobileにより自動的に更新されます。ハッシュはいつでも適切なURLとして更新されるので、どこでブックマークをしても正しいページへのリンクが作られます。ハッシュベースのURLではないものを取得するには、シンプルに # を除去してください。(注:#の直後がスラッシュ(/)の場合、絶対パスなので#以前をドメイン名の下まで、全て削除する必要があります)

フレームワーク内部では、ページの切り替えには、既にDOM上へロードされたものか、これからAjaxで読み込むものかに関わらず $.mobile.changePage() 関数が使われます。この $.mobile.changePage() には、ページを見つけて切り替えを行うための全てのロジックが内包されています。そこには例えば、ページが見つからなかった場合のレスポンスの扱いなども含まれます。そして $.mobile.changePage() は、外部から呼ぶことも出来ます。その際には、引数に(遷移先, 切り替え効果, 効果逆転, ハッシュ切り替え)を指定できます。「遷移先」は、遷移先を示す文字列(ファイルのURLや、ローカル要素のIDなど)か、配列(最初の添え字には遷移元、次の添え字に遷移先を格納)、あるいはオブジェクト(url, type(“get“または“post”), data(urlに付与するシリアライズされたパラメータ)を含む)を指定します。「切り替え効果」は、切り替えに用いる効果の名前(“slide“など)を渡します。「効果逆転」はブール値で、切り替え効果を逆方向に向けるかどうかを指定します。最後に「ハッシュ切り替え」はやはりブール値で、URLのハッシュを遷移先のものに更新するかどうかを渡します。

この $.mobile.changePage() 関数はjQuery Mobileのいたるところで使われています。たとえばリンクがクリックされた時、内部的にhref属性を標準化して $.mobile.changePage() 関数に渡しています。フォームがsubmitされた時にもjQuery Mobileはform要素の情報を収集し、シリアライズしたデータをやはり $.mobile.changePage() に渡します。また、ダイアログが開かれる場合にも同様に、ハッシュ切り替え無しの指定で $.mobile.changePage() を呼んでいます。これにより、ダイアログボックスの表示はページ遷移の履歴に残りません。

jQuery Mobileのナビゲーション・モデルにおける重要な要素として、他には base 要素が挙げられます。これは head の中に書かれ、ページ内の相対パス(css, 画像, jsなどの)を指定したパスにあわせるためのものです。ブラウザの中にはこの base 要素をきちんとサポートしていないもの(Firefox 3.6など)もありますが、jQuery Mobileでは全てのhref属性やsrc属性に正しく適用します。

参照されたページがDOMに埋め込まれると $.mobile.changePage() 関数は現在のページから新しいページへ切り替えを行います。ページの切り替え効果は、CSSアニメーション用のクラスを埋め込んだり取り除いたりすることで行われます。たとえば slide-left では、現在のページに “slideleft” と “out” というクラスが与えられ、また次のページに “slideleft”“in” そして “ui-page-active” が付与されます。切り替えアニメーションが終わると “in”“out” クラスは取り除かれ、遷移元のページからは “ui-page-active” クラスも失われます。

pushStateプラグイン

前述のようなハッシュベースの長いURLを、AjaxでリクエストしたURLそのままのクリーンなURLに変換するオプション機能があります。この機能は、ハッシュベースのURLを通常のURLに変換する際、その名前に反して history.pushState ではなく history.replaceState を用います。これは、フレームワークがターゲットとする端末上で、より安定的に動作するためです。この機能がオフになっているか、あるいは history.replaceState をサポートしていないブラウザ上では、依然としてハッシュベースのURLが使われることになります。

グローバル設定の $.mobile.pushStateEnabledfalse を設定することにより、この機能を止めることができます。

rel="external" と $.mobile.ajaxEnabled=false

ブラウザによる replaceState 実装の若干の違いが、特定の状況下で奇妙な動作を呼んでしまう場合があります。たとえば、デスクトップを含むいくつかのブラウザでは、既に push もしくは replace されたページから外へリンクして再び戻ってきた際に pupstate イベントが異なった挙動をする場合があります。jQuery MobileでAjaxナビゲーションを主に用いないサイトを構築する場合は、それが rel="external" をリンクに指定するのであれ、$.mobile.ajaxEnabled=false を指定して完全に停止させるのであれ、挙動を安定させるため pushState の機能を停止することをお勧めします。

changePage

フレームワーク上でページを切り替えたい場合、それが既にDOM上にロードされているページであれ、これからAjaxにより読み込みが必要なページであれ、 $.mobile.changePage() を使うことで実現できます。この $.mobile.changePage() には、ページの切り替えに必要な全てのロジックが含まれています。この関数は、順に遷移先(to)、切替効果(transition)、戻るかどうか(back)、ハッシュ変更の有無(changeHash)を渡すことができます。遷移先(to)には、文字列(遷移先のURLもしくはローカルの要素につけられたID)あるいは配列(最初のアイテムは遷移元となるページ、2番目のアイテムは遷移先のページ)、あるいはオブジェクト(プロパティにurl, type(“get“もしくは“post”), data(パラメータとしてシリアライズされるもの))を渡します。切替効果(transition)には、たとえば“slide“のような効果名を文字列で渡します。戻るかどうか(back)には、切替効果を逆回しにするかどうかをブール値で指定します。最後のハッシュ変更の有無(changeHash)には、ページ遷移が完了した際にURLを更新するかどうかをブール値で渡します。

この $.mobile.changePage() 関数は、jQuery Mobile内の至るところで使われています。たとえばリンクがクリックされた際、href属性に指定された値を使って $.mobile.changePage() が呼び出されます。フォームがサブミットされた際も、jQuery Mobileは内容をまとめてシリアライズし、やはり $.mobile.changePage() を使って代行します。同様にダイアログボックスがつくられる際も $.mobile.changePage() によりハッシュの更新無しにページが開かれます。これによって、ダイアログは履歴に残らずに制御できます。

ベースURL管理

jQuery MobileはHTTPリクエストを行う際、URLを絶対パスと相対パスの双方で使い分けます。 base> 要素のhref属性で指定されたベースURLは、ページ中の画像やスタイルシートなどの部品に使われることが多いです。この base 要素を動的に変更することを許していないFirefox3.6のようなブラウザでは、jQuery Mobileは全ての要素を走査して hrefsrc の属性値にベースURLを付与してまわります。

自動作成ページとサブハッシュURL

いくつかのプラグインには、ナビゲーションのためにページをダイナミックに切り替えていくものがあります。たとえばリストビュープラグインでは、階層構造化されたUL(あるいはOL)要素がそれぞれ異なったページとして掘り下げられていく形になります。これはdata^-url属性を与えられ、jQuery Mobileにおける通常の「ページ」のように動作します。しかしながら、こうしたリンクを動作させるには先にサーバからのリクエストが無ければなりません。そのために、プラグインにより自動生成されたページは次の特別なdata-urlの構造を用います: div data-url=“page.html&subpageidentifier”>

つまり、たとえばリストビュープラグインであれば、そのdata-url属性は次のようになります: data-url=“artists.html&ui-page=listview-1”

ページがリクエストされる際、jQuery MobileはURLを “&ui-page” の位置で前後に分け、実際のHTTPリクエストは前半部で行います。前述のリストビューの場合、URLは次のようになります: http://example.com/artists.html&ui-page=listview-1… そして、jQuery Mobileは artists.html をリクエストし、次に data-url が “artists.html&ui-page=listview-1” となっている div 要素をサブページとして作成し、現在のページとして表示します。

注意:この時 data-url 属性にはファイルのパスも指定します。単に “&ui-page=” 以降だけを記述しないでください。これによりjQuery Mobileでは、ひとつの機構でURLとの合致だけで内部ページを見分けられるようになります。

Ajaxによるナビゲーションを使わない場合

次のような場合は、Ajaxを用いず通常のHTTPリクエストが行われます。まず、リンクが異なるサイトへのリンクである場合。次に、リンクに次のような属性を指定した場合です。

  • rel=external
  • target (値が、たとえば “_blank” など何であれ)

フォームからの送信

フォームのサブミットも、自動的に同じナビゲーションモデルで扱われます。詳しくは フォーム を参照してください。

アプリケーション・キャッシュの利用

アプリケーション・キャッシュをjQuery Mobileと共に使う場合、注意しなければならない問題がひとつあります。いくつかのブラウザでは、キャッシュからのリクエスト取得が成功した際に、HTTPステータスとしてゼロを返すということです。これを、jQueryコアの $.ajax はエラーと判断してしまいます。アプリケーション・キャッシュの効果を得るには、jQuery Ajaxのプリフィルタを使うようにしましょう。たとえば、次のようにします( jammus による )

$.ajaxPrefilter( function(options, originalOptions, jqXHR) {
        if ( applicationCache &&
                 applicationCache.status != applicationCache.UNCACHED &&
                 applicationCache.status != applicationCache.OBSOLETE ) {
                 // the important bit
                 options.isLocal = true;
        }
});

この例にある isLocal を true に設定しているのは、このAjaxリクエストが通常のHTTPリクエストの返すゼロとは異なる意味を持つことを通知するためです。ローカル・リクエストは、たとえばステータス・ゼロに対して似たような動作をします。jQueryコアはXHRの responseText を見て、果たしてリクエストが成功したかどうかを判別するようになります。

重要な注意点として、上記の isLocaltrue を設定する解決策は、全てのAjaxリクエストに対してマニフェストにあるかどうかや、キャッシュが妥当なものであるかなどの検証を不確かにしてしまうことです。現時点では、これは特に問題にならないでしょう。なぜなら、jQueryコアはHTTPステータスがゼロの場合のみ isLocal であるとみなすため、キャッシュされていないリクエスト結果に対しては影響を及ぼさないからです。しかし、このように isLocal 設定がステータスのゼロを扱うためだけに独立したままで、いつまでもいる保証はありません。この動作が将来的に変えられた場合、アプリケーションがおかしくなってしまうかもしれません。

既知の制限

特殊な環境下で作られたjQuery Mobileページでは、ナビゲーションを構築する際に注意が必要になる場合があります。

  • URLにファイル名を指定せず、ディレクトリへリンクする場合(たとえば href=“typesofcats/index.html” ではなく href=“typesofcats/” のような)、最後のスラッシュを省略できません。なぜならjQuery Mobileは、最後にスラッシュが無い場合、最後をファイル名とみなして相対パスを作る際に1階層上に見てしまうからです。
  • Ajaxによる読み込みでは、DOMの中で最初に見つかったページだけを取り込みます。開発者は、読み込まれた後のページ内で要素の関係が変わってしまうことにより起こる混乱を避けるよう、ID属性の管理をしっかりとする必要があります。
  • 複数ページテンプレートのページにリンクする場合、リンクには必ず data-ajax=“false” を指定するなどしてページ全体がリフレッシュされるようにしなければなりません。Ajaxリクエストでは、前述の通り最初のページのみを使用するためです。これは現在 サブページ・プラグイン を使うことで解決可能です。
  • ページ特有の外部ファイルは、jQuery Mobileで作られたサイトにおいては “page” 要素(data-role=“page“で指定された要素)内で読み込むべきです。例えばスタイルやスクリプトは、ページ要素内に書きましょう。更に良いのは、jQuery Mobileのページイベントによりロード時に読み込み用のスクリプトを用いることです。
  • 逆に、サイト全体で共有するようなパーツは head 要素の中でHTMLとして呼ぶか、あるいは最低限、ページ要素の外で読み込むべきです。ページ内に入れると、実行される都度、繰り返し読み込まれてしまいます。
  • 前述の通り “ui-page” はサブハッシュ用のキーとして用いられます。ここに指定された値は jQuery.mobile.subPageUrlKey に格納されます。
  • 以前に読み込まれたjQuery Mobileによるページを、pushStateを有効にした状態で再訪した場合、ブラウザによっては popstate イベントを呼んでしまうような場合があります。もしサイトが定常的に外部へのリンクを持ち、アプリケーションがおかしな挙動をしていると感じたら、pushStateの機能を停止させてみてください。
  • jQuery Mobileでは、内部や埋め込みページに対してクエリー・パラメータを通すことをサポートしていません。しかし、次の2つのプラグインが、この機能を補完してくれます。ひとつは page paramsプラグイン という軽量のもので、もうひとつは jQuery Mobile routerプラグイン で Backbone.js や Spine.js を制御するための、より高機能なプラグインです。
  • ハッシュベースのURLを用いている関係上、通常のHTMLにあるようなリンクにハッシュ(#fooなど)を指定して設定位置までジャンプするような機能は対応されていませんでした。かわりに $.mobile.silentScroll を使うことで、指定した縦位置にスクロールすることができます。引数 yPos に、スクロール先の縦座標を指定してください。