そろそろjQuery Mobileでajaxを無効にしてるやつに一言いっておくか
jQuery Mobileでは、ページ遷移の際に自動的にajaxが利用されています。特に何もしなくても遷移先のページをajaxで取得してアニメーションをつけて遷移するというのがjQuery Mobileの大きな特徴のひとつになっています。
しかしながら、巷では、何か問題があるとすぐにこのajaxを無効にするという対処方法が蔓延しているようです。ちなみにajaxを無効にする方法というのは、以下のようなものを指します。
- a要素やform要素に data-ajax="false" を指定する。
- グローバル設定で $.mobile.ajaxEnabled = false; を設定する。
もちろん、このajaxの挙動を理解した上で、ajaxを無効にするという方法を取ることは何ら問題ないのですが、とにかく困ったらajaxを無効にするということが多いようです。
具体的には以下のようなケースが挙げられるでしょう。
- ページ遷移が遅いからajaxを無効にする
- Google AnalyticsやAdSenseを入れるためにajaxを無効にする
- スクリプトが動かない、スタイルが効かないから無効にする
- 何か問題があると取り敢えずajaxを無効にしてみる
(2012/04/12 追記)
次のパターンも注意が必要なのでこちらに載せておきます。
- 同一ドメイン上に安全でないリソースがある可能性がある場合
これらのケースについて、個別に対処方法などを解説していきたいと思います。
ページ遷移が遅いからってajaxを無効にしない
よく誤解されがちなのが、ページ遷移が遅いという問題です。たしかに、Android端末では特にCSS周りの実装が怪しく、アニメーションがやばい感じですが、それを除けばajaxを有効にしたほうが確実に早いです。
なぜなら、ajaxでは遷移先のページの最初のdata-role="page"の要素のみを切り出して読み込むからです。head要素内ののscript要素やstyle要素は一切読み込まないため、余計なリクエストは発生しません(まあ、この読み込まないという部分が後述する問題にもなっていますが)。
アニメーションが遅いのであれば、アニメーションをオフにすれば良いだけなので、ajaxとは別に考えましょう。
アニメーションを無効にする
$(document).bind('mobileinit', function(){ $.mobile.defaultPageTransition = 'none'; });
また、リンクをタップしてからページ遷移するまで遅いという人は、vclickイベントでページを遷移するようにチューニングしてみると良いかもしれません。Webkit系のブラウザでは、clickイベントなどはdouble tapなどの判定のために、300msほどの待ち時間が発生するので、代わりにvclickイベント使えばすぐに反応するようになります。vclickイベントはtouchイベントとclickイベントを統合したjQuery Mobile仮想イベントです。
vclickイベントでページ遷移する
$(document).delegate('a', 'vclick', function(e){ e.preventDefault(); var link = $(this); $.mobile.changePage(link.attr('href'), { transition: link.jqmData('transition') }); });
(delegate自体が遅いとか、changePageの引数が足りないとかは自身でカスタマイズして使ってください)
あとは、ページ要素へのdata-dom-cache設定や、リンクへのdata-prefetch設定などもあるので、うまく使ってチューニングしてください。
Google AnalyticsやAdSenseを入れるためでもajaxを無効にしない
ページの遷移方法が、通常と異なるために、単純にコードやHTMLを貼りつけただけでは最初のページ以外ではうまく動作しません。これは、下記エントリで既に書いたので、参照してください。Google AdSenseは使ったことないので、なんとか自力で頑張ってください。
スクリプトが動かない、スタイルが効かないからってajaxは無効にしない
遷移先のページをajaxで取得して、ページ要素のみを切り取るので、他の部分に記述したスクリプトやスタイルは読み込まれません。そのため、最初に読み込まれるページですべてのスクリプトやスタイルを読み込む必要があります。ページ表示時に発火するpageshowイベントやページのイニシャライズで1回だけ発生するpageinitイベントなど、ページ関連のイベントをうまく使ってください。
pageshow(ページ表示のたびに毎回発生)
$(document).delegate('#page1', 'pageshow', function(){ // 情報の更新やトラッキングなど });
pageinit(ページのイニシャライズで1回のみ発生)
$(document).delegate('#page1', 'pageinit', function(){ // スクリプトによる静的要素の追加やイベントの登録など });
また、ここで作成した全ページ共通のスクリプトやスタイルを、全ページに埋め込んでおいてください。なぜなら、どのページが最初に読み込まれるからわからないからです。途中のページでブラウザのリロードを実行しまうと、そこが基点になってしまいます。逆に、全ページに埋め込んでも、読み込まれるのは最初のページだけです。他にもどうしても、ページごとに書きたいという場合は、ページ要素の中にスクリプトを書くという手もあります。
スクリプトやスタイルをページ要素に含める
<div data-role="page"> <script> // 何か </script> </div>
何か問題があっても取り敢えずajaxを無効にしない
とりあえず、何か問題があったらバグだと早計する前に、挙動をひとつひとつ確認して対処しましょう。ajax無効にするのであれば、Twitter Bootstrapなどのデザインフレームワークだけを使うとか、もしくは一から作るとかしたほうが良いと思います。(jQuery Mobileはデザインフレームワークだけで使うには巨大なので)
(2012/04/12 追記)
同一ドメイン上に安全でないリソースがある可能性がある場合
ajaxによるページ遷移は、URLから実行することが可能なため、同一ドメイン上に安全でないリソースがある場合は注意が必要です。例えば、ユーザーが自由にアップロードできるフォルダがあるとか、共有ドメインを使ってる場合などです。そういう場合には、pagebeforeloadイベントを使ってチェックしましょう。
$(document).bind('pagebeforeload', function(e, data){ var isValid = false; // ホワイトリストなどでajax遷移できるアドレスを制限する if ( !isValid ) { e.preventDefault(); data.deferred.reject(data.absUrl, data.options); } });