2012 年 5 月 17 日

jquerymobileでdomCacheを止める

HTML5+jQueryMobile

jQueryMobile(以下、jqm)は、パフォーマンスを向上させるために、domをキャッシュします。静的ページなら問題ないのですが、動的コンテンツでは、このキャッシュが弊害となるケースがあります。

たとえば、入力画面から入力エラー内容を伴って元の入力画面へ戻るような場合は、同じページコンテンツが返ってきますので、domの中に同じidを持つdivタグがキャッシュされることがあります。

このキャッシュは、$.mobile.page.prototype.options.domCache = falseであっても、有効なようです。jqmは遷移する前後のページを保持して遷移のビジュアルエフェクトを実現するので、このキャッシュは必須なんだろうと考えています。

そもそも、何が弊害かというと、documentの中に同じidを持つdiv(data-role=”page”を持つdivです。以下ページとします)タグがあると、このページにイベントハンドラ(たとえば、pageinitハンドラ)を動的bindさせても、アクティブな方のdivにバインドされないという現象が発生しました。

idは同じなのですが、幸いCSSクラスで判断することが可能です。

classに.ui-page-activeクラスがある方が有効なページですが、onで動的バインドさせるときに、正しくセレクトしてくれません。動的バインド時には、このクラスが適用されていないように見えます。

jqmではidはドキュメントでユニークではなく、全体でユニークとすることになっていますが、キャッシュしているページコンテンツはidではなく、data-urlで識別しているように見えます。ですから、jqmではこのようなidの重複は問題ないのかもしれません。

動的ページが多くあるため、私たちはあらかじめ全てのページに別々なidを与えて、最初に全てのページのpageinitハンドラを動的bindしています。異なるページがロードされるたびに、適切なpageinitハンドラをbindさせるという方法です。そのため、現在アクティブなページをセレクトできないとページの初期化ができないということになります。

これを解決するために、domに同じidのページが存在しないようにしてみようと、以下のスクリプトでページを削除することを試してみました。

/* clear cache page */
$(document).on('pagehide', function(event, ui) {
  var page = $(event.target);
  page.remove();
});

こうしてやることでdomにはいつも一つのページしか存在しないようにはできました。ページ遷移のビジュアルエフェクトにも問題ないように見えます。

aタグにrel=”external”を指定してやると、ajaxせずに通常のhttpでキャッシュせずに読み込んでくれますが、ページ遷移のビジュアルエフェクトはまったく効かなくなります。また、$.mobile.chagePageメソッドで遷移しているところは、そのようなオプションが見当たりません。

今のところ、副作用はありませんが、本当にこれでよいのか、もう少し様子を見たいと思います。