GAEの値上がりでテンションだだ下がりなので ちょっと気分を変えて jQuery Mobile のノウハウを整理してプラグイン化してみた。 ちょうど 1.0正式版がリリースされたし。

P.S. 「 JQMDP 1.0b2 公開します。」で正式版公開しました。

JQM でスマホのネイティブアプリっぽい事をやろうとすると 動的ページをJavaScriptでごりごり書かないといけないのだが JQM はあまりその辺を助けてくれる機能が無い。

そんなに複雑な事でなくテンプレ内のテキスト、画像、リンクの 差し替え位の事がしたいだけなのだが結構めんどくさい。

と言うわけでざっくり プラグインの機能をまとめると

  • テキスト、画像、リンクとかの差し替えがしたい。
  • 配列なんかを勝手にリストに変換してほしい。
  • 部品化したテンプレをあちこちで参照したい。
  • id="〜"なんか衝突しちゃうから使いたくない。
てな感じだ。 4番目は少し規模が大きくなると結構大事だ。

詳細な仕様/デモ/Downloadはこちら。

  • 仕様:http://wsjs-gae.appspot.com/jqmdp/
  • Download: http://wsjs-gae.appspot.com/jqmdp/js/jquery.jqmdp-1.0b.js

とりあえず実装方法としては data-dp-〜 と言う拡張属性を定義して そこに小さいJavaScriptを書くといい感じに処理してくれるって事にした。

具体的にはこうだ

<div>Date: <span data-dp-text="(new Date())"></span></div><div>Date: <span>Mon Nov 21 2011 22:25:20 GMT+0900 (JST)</span></div> になる。 いい感じじゃね?

リストはこうする

<div data-dp-scope="({list:window.location, key:0})"> <ul data-dp-for="(key in list)" data-role="listview" > <span data-dp-text="(key)"></span> = <span data-dp-text="(list[key])"></span> </ul> </div>
  • 見たまま、HTMLの中に JavaScript を書いている感じ。
  • data-dp-scope はこのタグの中だけで使えるローカル変数を定義している。
  • ループ引数の key を data-dp-scope で定義させるのがちょっとダサイが現状やむ無し。
<div> <ul data-role="listview" > <li><span>hostname</span> = <span>localhost</span><li> <li><span>port</span> = <span>8080</span><li> <li><span>hash</span> = <span>#attrs2</span><li> : </ul> </div> になる。

部品参照はこう、(☆評価サンプル)

<script src="js/parts/rating/Rating.js"></script> <div data-dp-scope="(new Rating($this))"></div> <div data-dp-scope="(new Rating($this))"></div>
  • Rating()のコンストラクタが実行されると Rating.html の内容が埋め込まれるようになっている。
  • 2つ有るが其々が値を保持できる。

実行結果(これは画像、動くのはここ):

部品コード定義:(js/parts/rating/Rating.jsに配置) function Rating(){this.initialize.apply(this, arguments)}; (function(Class){ var This = Class.prototype; // リソースの相対パスを絶対パスに変換している。 var TEMPL = $.jqmdp.absPath("Rating.html"); var IMG_ON = $.jqmdp.absPath("star-1.0.png"); var IMG_OFF = $.jqmdp.absPath("star-0.0.png"); // コンストラクタ This.initialize = function($this) { this.$this = $this; this.value = 0; // Rating.htmlをテンプレート適用。 $.jqmdp.exTemplate($this, TEMPL); } // 値を変更して再描画 This.val = function(v){ this.value = v; $.jqmdp.refresh(this.$this); } // on/off の☆の画像を帰す This.star = function(v){ return (this.value>=v) ? IMG_ON : IMG_OFF; } })(Rating);

部品テンプレート定義:(js/parts/rating/Rating.htmlに配置)

<div> <img data-dp-src="(star(1))" onclick="$(this).jqmdp('scope').val(1)" /> <img data-dp-src="(star(2))" onclick="$(this).jqmdp('scope').val(2)" /> <img data-dp-src="(star(3))" onclick="$(this).jqmdp('scope').val(3)" /> <img data-dp-src="(star(4))" onclick="$(this).jqmdp('scope').val(4)" /> <img data-dp-src="(star(5))" onclick="$(this).jqmdp('scope').val(5)" /> </div>
  • $(this).jqmdp('scope') は参照元の data-dp-scope="(new Rating($this))" の値を帰す。 したがって、onclick は Rating.val() が呼ばれる。
  • data-dp-src="(star(n))" は参照元の data-dp-scope="(new Rating($this))" のスコープで評価されるので省略しても Rating.star() が呼ばれる。
  • data-dp-scope を使う事で id の使用を回避できている。

と言うような感じで動いている。

簡単にやっているように書いたが実は結構大変だった。 JQMは挙動が良く分からない所が有ったりするし HTML上にローカルスコープが有るように見せかけるのは結構トリッキーな実装になっている。

それと属性名が長い。 HTML5の規約で data- が必要なんだけど衝突を考慮するとさらに プレフィックスを付けて data-dp- にしなきゃいけない。 実は、dp- だけで試して見たのだが普通に動いた (^^;。 実装依存になりそうだったので諦めたが。

尚、Chrome,Firefox,iPhone でしか動作確認していない :-P

参考サイト:

  • http://dev.screw-axis.com/doc/jquery_mobile/
  • http://d.hatena.ne.jp/pikotea/20101019/1287484040
  • http://billboardtop100.net/BLOG/jquery-mobile/cat18/
  • http://kachibito.net/web-design/19-jquery-mobile-tips.html
  • http://hisasann.com/housetect/2011/02/jquerymobile.html
  • http://hisasann.com/housetect/2011/06/jquerymobile_1.html