2012 年 5 月 7 日

pagebeforechangeは二度呼ばれる

HTML5+jQueryMobile

jQueryMobile(以下、jqm)のデフォルトページ遷移はajaxで行っていますが、これに頼らず自力で表示内容をajaxで取得して遷移したいときは、pagebeforechangeイベントハンドラを使って、表示内容を生成します。しかし、jqmで必要な処理や、気をつけないといけないことがあります。

詳しくはjQuery Mobile and Dynamic Page Generationに書かれていますので、このサンプルを元に簡略化して説明します。

このページのサンプルコードでは、pagebeforechangeイベントハンドラで以下のような判定を行っています。なぜ、こんな判定をするのかというと、pagebeforechangeイベントは再帰的に呼ばれる可能性があるからです。

この後の処理で、もう一度、changePageメソッドを呼ぶ必要がある(サンプルのshowCategoryメソッドの中)のですが、changePageメソッドから、再度pagebeforechangeイベントが呼び出されます。それを区別するためのif文です。

“pagebeforechange being called twice”(pagebeforechangeは二度呼ばれる)でも説明されています。

$(document).on('pagebeforechange', function(e, data) {
  if (typeof data.toPage === 'string') {
    // 遷移先のURLが文字列として格納されています。
    // こちらの分岐で、コンテンツをロードします。
    $page = $('#page'); // data-role-id=pageのdivタグ
    // ajaxでpageの内容を生成する。
    $page.page(); // jqmのウィジェットに拡張する。
    $.mobile.changePage($page); // もう一度、chnagePage()を呼び出す。再帰的に、このfunctionが呼ばれます。
    e.preventDefault(); // 以降のイベント処理を実行しないように。
  } else {
    // data.toPage($page)は遷移先のDOMオブジェクト。
    // 8行目のchanePage()から呼ばれて到達します。
  }
});

ajax(ここのajaxは同期型で呼ばないとまずいと思います)でjqmでマークアップしたコンテンツを読み込んだら、jqmウィジェットとして拡張してあげる必要があります。もちろん、jqmのマークアップがないものなら、page()メソッドは必要なさそうです。

また、jqmのビジュアルエフェクトを有効にしたければchangePage()する必要があります。

このあたりのjqmの動作をよく理解しておかないと、思ったように動作しないということになりそうです。

私のプログラムはpage()もchangePage()も必要なさそうだし、実際、今のところ問題ありませんが、とりあえず呼んでいます。