なんらかのアクションに対して、外部ファイルを読み込みたいときってあるよねー。
Ajax的なものを作ろうとしてぶつかった沢山の壁について書いてます。
まずは表題の話。
JavascriptのinnerHTMLで<&SCRIPT>タグを表示しようとすると、なぜか何も出ない。
同じようなことをした人はみんなぶつかる壁だと思うけど、バグでもなんでもないんです。
MSのinnerHTMLの仕様にあるんですが、
When using innerHTML to insert script, you must include the DEFER attribute in the script element. |
スクリプトを挿入するのにinnerHTMLを使用するとき、あなたはスクリプト要素でDEFER属性を入れなければなりません。 |
文章そのまま、<SCRIPT>タグに「defer="defer"」を入れないといけないってことです。
要するに「マイクロソフトの仕様」でした。
※それプラス、IEのバグとして、SCRIPTタグの開始の<の前に何かスペースでいいから文字をつけないといけないかも。
まぁそれはいいんだけど、deferを入れることにより発生する弊害があるから困る。
そもそもdefer属性ってのは、処理を後回しにするための機能です。
HTML文の解析が上から順番に行われて、<SCRIPT>タグの所で処理が停止されては困る場合、
deferを入れることによって<SCRIPT>タグの解析を後回しにして、タグの先にあるHTML構文を解析します。
しかしこれは、<SCRIPT>タグ内で出力が行われない場合は正常に動作しますが、document.writeが存在すると、実行タイミングが不定なのにページへの書き込みが行われるため問題が発生します。
そのため、そもそもdeferを入れて解析を後回しにするときは、document.writeを使ってはいけないことになっています。
(これはJavaScriptの仕様です。
※ijnnerHTMlは使用可能なので、使い方次第では文字列出力も可能です。
ここから個人的な実装の話。
・外部ページを読み込んで表示する必要があるが、ActiveXオブジェクトを使いたくない。
↓
・innerHTMLで<SCRIPT>タグを書き込んで、タグの読込先外部ファイルの中でdocument.writeする方法を考える。
↓
・innerHTMLに<SCRIPT>タグタグが使用ができない(IEの仕様
↓
・使用するためには、deferをセットした上で、scriptタグの前に何かを描画しておく。
例:" <SCRIPT type='text/javascript' defer='defer'>alert('動くよ')</script>";
↓
・deferはscriptの動作を後回しにするための構文で、これを入れると文字列の書き込み(document.write)が使用できない。
↓
・具体的には、document.writeを使用すると、ページが丸ごとリセットされてから書き込まれる。
↓
・なので、innerHTMLに書き込んだ<SCRIPT>タグが読み込む先のページでinnerHTMLで書き込むという方法を試す。
具体的には、本来書き込まれるべき場所のidを渡すことによって、読込先の外部のScriptから文字列の書き込みを行う。
↓
・getで値を渡す際に&を使うと、innerHTMLへ入れたときにエンコードされて「&」になってしまう。
それが原因でスクリプトが止まる。(スクリプトから実行するURLに「;」が含まれていると動かんのか?)
↓
・ゲットつなげちまって、後からセパレートできるしかねぇな('A`)
・innerHTMLに書き込んでいるのとまったく同じスクリプト文を、普通に書いたら動くのに、書き込んでるのは動かない。
↓
・結論として、innerHTMlを使って埋め込んだscriptタグの中のscriptを実行するのは不可能なんじゃないか?ッツー結論にいたった。
ってことで、数時間かけてけっきょくあきらめた。
誰か成功した人いたら、おせーてくださいほんと。
確認画面で、タグが全て吹っ飛びました。
もう一度書き直します。
http://d.hatena.ne.jp/shogo4405/20061210/1165819217
というdocument.write()をオーバーライドする方式を試してみましたが、
IEではうまくいきませんでした。
現実的には動的に書き換えたい箇所を
document.write()ではなく、id付き<span/>を配置し、全体をinnerHTMLした後に、
改めてidを付加した<span>に後付けでinnerHTMLするしかないと思います。
prototype.jsのeach()を使えば、
本来document.write()したかったオブジェクトの名称と<span>のidを結びつけることが可能だと思います。