そろそろjQuery Mobileでajaxを無効にしてるやつに一言いっておくか

jQuery Mobileでは、ページ遷移の際に自動的にajaxが利用されています。特に何もしなくても遷移先のページをajaxで取得してアニメーションをつけて遷移するというのがjQuery Mobileの大きな特徴のひとつになっています。
しかしながら、巷では、何か問題があるとすぐにこのajaxを無効にするという対処方法が蔓延しているようです。ちなみにajaxを無効にする方法というのは、以下のようなものを指します。

  • a要素やform要素に data-ajax="false" を指定する。
  • グローバル設定で $.mobile.ajaxEnabled = false; を設定する。


もちろん、このajaxの挙動を理解した上で、ajaxを無効にするという方法を取ることは何ら問題ないのですが、とにかく困ったらajaxを無効にするということが多いようです。
具体的には以下のようなケースが挙げられるでしょう。

  • ページ遷移が遅いからajaxを無効にする
  • Google AnalyticsAdSenseを入れるために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 AnalyticsAdSenseを入れるためでもajaxを無効にしない

ページの遷移方法が、通常と異なるために、単純にコードやHTMLを貼りつけただけでは最初のページ以外ではうまく動作しません。これは、下記エントリで既に書いたので、参照してください。Google AdSenseは使ったことないので、なんとか自力で頑張ってください。


jQuery MobileでGoogle Analyticsを使う方法

スクリプトが動かない、スタイルが効かないからって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);
  }
});