Archive for 5月, 2011

[IE6|IE7|IE8]cloneNodeで複製したエレメントのidをjQueryから参照出来ない時のTips


2011
05.23

皆さんこんにちわ、なんだか冷えますね。

 

さて、皆大好き IE ブラザーズのお茶目な仕様で少々ハマりましたので仕様解説と解決策の TIPS です。

実は基本的な事かもしれませんが、仕様を理解しておくのに越した事は無いでしょう。

リッチコンテンツ制作時にちょこちょこ問題になる可能性が高いので、便利な関数も作ってみました。改良して使ってもらえればよろしいかと思います。

 

出くわした状況

メニューをスライドしたい時に数がギリギリなので、一番端の要素を予め逆側に複製しておいてスライドした後に複製したエレメントを消去しようとした。

 

症状

IE だけスライドした後に複製元となったエレメントが動き出して、思い通りの動きをしなかった。

 

元ソース

■html

1
2
3
4
5
<ul id="listBox">
    <li id="list1">hoge</li>
    <li id="list2">moge</li>
    <li id="list3">foo</li>
</ul>

■javascript

1
2
3
4
5
6
7
var content = document.getElementById('listBox');
var clone = document.getElementById('list1').cloneNode(true);
clone.id = 'temp';
clone.style.position = 'absolute';
clone.style.left = '600px';
content.appendChild(clone);
$('#temp').animate({left: 400});

 

cloneNode して、id を書き換えて親要素に appendChild して動かそうとした訳です。

IE 以外のブラウザはこれで問題無く動きます、IE 以外は。

IE だけは #temp を呼ぶと複製元である #list1 を参照して、そちらを動かそうとします。ちなみにリスナを仕掛けたり、setTimeout でぐるぐる回してフラグを監視して、存在確認をした後に命令しても一切を無視して複製元を動かします。
更に jQuery から attr を使って id を変えても駄目です、凄い頑固ちゃんです。

 

早速原因を追求していくと、どうにも困った事になっていました。

 

IE は同一プロセス内で cloneNode(複製)されたエレメントは、別プロセスから呼ばれない限り複製元の id を参照する。

 

え、なんで!?と言う仕様ですよね、cloneNode(複製)したプロセスとは別にボタンを用意して、適当に命令を書いた関数を呼び出すと思い通りの動きをします。

もしかしたらちょっと違うのかもしれませんが、大体こんな感じの挙動になる筈です。

 

 

非常に気持ち悪いです。

 

 

ともあれ fix していきましょう、要は cloneNode(複製)したエレメントの挙動がおかしいのならば新規でエレメントを生成して、複製元のエレメントもしくは複製したばかりのエレメントから欲しい情報を新規エレメントに移してから appnedChild すれば良いのです。

 

改良版ソース

■javascript

1
2
3
4
5
6
7
8
9
10
11
12
13
var content = document.getElementById('listBox');
var clone = document.getElementById('list1').cloneNode(true);
var elm = document.createElement('li');
content.appendChild(getCloneNode(clone, elm, 'temp'));
$('#temp').animate({left: 400});

function getCloneNode(clone, elm, id) {
    elm.id = id;
    elm.style.position = 'absolute';
    elm.style.left = '600px';
    elm.innerHTML = colne.innerHTML;
    return elm;
}

 

 

こうやると意図した動きになるはずです、なんだか回りくどいけど。

これは複製したエレメントから新規エレメントに要素を移していますが、多分複製せずに直接突っ込んでも上手く行きそうですね。別処理との兼ね合いで content を外で作ってますが、全部関数内でやっちゃった方が綺麗にかけそうですね。

 

そこはお好みで。

 

なんか悔しかったから複製してやっただけですし。

 

それではまた。

 

[iPhone/iPad]WebApp制作における読み込み時間/オフライン問題


2011
05.18

皆さんこんにちわ、最近随分日が長くなったなぁとしみじみ思います。

そして随分書きかけのエントリーが溜まって来たなぁと思います。

消化しないとただの豪華なオンラインメモ帳になってしまいます、これはいけません。

 

そう言う事も踏まえてなお、単発ネタです。

iPhone / iPad をターゲットにした WebApp でネックになるのは読み込み時間とオフライン時の挙動です、普通にブラウザアプリを作る感覚で行くと下記のような問題にブチ当たります。

  • ページ遷移の度に読み込んでたらストレス溜まる
  • かと言って全部最初に読み込んでおいてメモリに展開すると色々と苦しい
  • そもそもオフラインだとページ遷移とか非同期通信自体不可能じゃない

ネイティブアプリは全てローカルにリソースを置く事で回避出来るのですが、Web ブラウザを使っている以上このような問題が起こります。

 

困りました、調べました、解決しました。

 

なんの事は無い、iOSAndroidWEB Database API を実装しているじゃないか。良く考えると双方 Webkit 系だもんね、今更気づいたのかよ!と言わざるを得ません。てへ。

この API はブラウザの JS から双方のネイティブアプリを触っている方はお馴染みの SQLite3 へとアクセスする事が出来ます、つまり始まる前に全部ローカルにデータを保存しておく事が出来ます。ちょっと試した事が無いのですが blob 型が有るのでバイナリも突っ込めるはず。

そしてもう1つの問題、オフライン時にページを開こうとしたりリロードしたりしようとすると「ページを開けません。インターネットに接続していません。」みたいなエラーが出るのですが、これも .manifest を使えば回避可能です。

オフラインだとこうなります

これは強力なキャッシュ機能で、指定したファイルを全てローカルに保存して次回からはとにかくここから読み出すようです。中身を更新したい時は .manifest の中身の文字を1文字でも変えれば再構成されるようなので、ページの要素を読み込む前に .manifest のチェックが先に実行されているみたいです。

要するにバージョン管理をきちんと行い、.manifest にはそのバージョン名を入れておけば常に最新の状態をユーザーに提供出来ると言う訳ですね。

 

さて、これで…かなりネイティブアプリに迫る事が出来るようになったハズです。

思っていた以上に私は WebApp について解っていなかったのがショックですが、これで同じ土俵には上がれたと思うので益々精進したいと思います。

 

それではまた。

 

 

[iPhone/iPad]WebAppのクラス設計について


2011
05.17

 

皆さんこんにちわ、お久しぶりです。

GW 以降バタバタしておりましたが一段落したと言いたい所ですが、この業界の三大職業病「肩こり」「腰痛」「イボG」のウチ、堂々の二冠達成と言う偉業を現在進行形でございます。

 

ちょっと単発ネタです。

先週は在宅勤務で引きこもっていたのですが、何もただ単に引きこもっていた訳ではありません。

仕事や家事や PSP でミクさんを愛でる時間の合間をぬって、iPhone / iPad 用の WebApp の開発を行っていました。今回構築しているアプリのベース部分が完成して、初代 3G なんかも引っぱり出して来てニヨニヨとしていたのですが…ここからエフェクト系を山盛り入れるには、とてもじゃないけどメモリが足りない事に気づきました。

 

だって既にちょっと重いもん。

 

画像や音声ファイルのロードは最初からネックになる事は解っていたのですが、JS で生成しているオブジェクトと我らの味方の jQuery が重たくてしょうがないのです。

 

安定性を欠くようではリリースなど片腹痛い訳で、これはもう基礎部分から再設計を余儀なくされた状況です。

リソースをふんだんに使うタイプの WebApp 開発にあたり、今回解った事は下記。

  • jQuery は使わない方が良さそう
  • prototype 定義を最大限使わないとキツい
  • Ajax による リソースの loader 部分がかなりマゾい
  • ダイナミックな動きは全部 CSS3 で賄う

1つ目は単純にライブラリよりネイティブの方が早い、当然ですね。クロスブラウザ対策が必要ないのでそこまで恩恵がある訳では無いので外す方向で行こうと思った。
そうなると要素に対して CSS3 を適応させる部分は大丈夫なんだろうか、とかの不安が残る。

 

2つ目は調子に乗って何個かインスタンスを作っているとメモリがアワワな事になる、昔 prototype 汚染にトラウマ級の悪さをされて以来食わず嫌いになっていたがそんな事言ってられなくなった。
これは私の設計の甘さもあるのですが…ガベージコレクションを使う手もあるんだろうか。

 

3つ目は WiFi 環境なら余裕で無視出来るレベルなのですが、貧弱な 3G 回線だとメディアファイルの load 時間がかなりストレスになる。しかし全てのファイルを始めに読み込んでおくのは 3G や 3GS のメモリ量だと厳しい感じがするので、先読みアルゴリズムを極限まで詰めて解放/読み込みをこまめにやるべき…?
逆にキャッシュの限界量に合わせてリソース側に制限をかけるべき…?

 

4つ目は jQuery を解雇するなら当然変わりにアニメーションを担当するものが必要になる、これは使ってみた感想だけど CSS3 でアニメーションさせると jQuery の何倍も何十倍も綺麗に動くので他に選択の余地は無いと思った。
canvas を使う手もあるのだけど、html5 で組むからこそ意味があると思っているので FLASH 的な動き(むにゃむにゃ動く背景とか)の時だけ使うのが良いと思う。

 

世界的にまだまだ開拓途中のこの WebApp と言う世界、今後のスマートフォンの主力コンテンツとしての活躍が期待されているのでやり甲斐があって楽しいのですが…

 

WebApp は開発サイクルが短くて予算節約になりますよ!

 

と言う売り文句を言えるようになるまでが大変そうです、セオリーは俺が作る!ぐらいの気概は必要ですね。

 

それではまた。