window.onload 前でも DOM 処理が可能なら通知してくれる domready.js
DOM 読み込み完了のタイミングで、任意の関数を実行できるようにする JavaScript ライブラリを書いてみた。
mootools の同様の機能を基にしていて、単体として使いやすいように外部ライブラリへの依存性をなくし、prototype.js とも併用できるようにしたもの。
現状、手元の環境では以下のブラウザで動作確認済み。
- IE 7 (XP standalone)
- IE 6 SP2
- Firefox 2.0.0.4
- Opera 9.21
- Safari 2.0.4
- Mac Firefox 2.0.0.4
- Mac IE 5.2.3
ただし、Mac IE では window.onload で代用するように実装してある。まあ、スクリプトエラーが出るよりマシだろう。
使い方
まず、domready.js を読み込む。
<script type="text/javascript" src="/javascripts/domready.js"></script>
prototype.js と併用する場合は prototype.js より後に読み込む。
<script type="text/javascript" src="/javascripts/prototype.js"></script>
<script type="text/javascript" src="/javascripts/domready.js"></script>
あとは、DOM 読み込み完了のタイミングで実行したい関数を Event.domReady.add で登録するだけ。
Event.domReady.add(function() {
...
});
他のイベントと登録方法が異なるのは直感的じゃない、とか言われそうだけど、正直あんまり気にならない。
経緯: window.onload の欠点
多くの Ajax 系実装では、ページ読み込み完了時に初期化などを実行するようになっている。
Event.observe(window, 'load', function() {
...
});
これは prototype.js によるイベント処理だが、window.onload イベントで処理を実行するために、関数を登録しているのが分かるだろう。
わざわざこんなことをしているのは、DOM を操作したいからだ。
だから、ほとんどの Ajax 系実装は window.onload イベントがやってくるのをじっと待っている。window.onload イベントのあとでは DOM ツリーは完全に構築されているし、他に DOM ツリーが構築済みなのを知る、適当なイベントもないからね。
もちろん、window.onload は完全じゃない ... いや、それは嘘で、完全すぎる。DOM ツリーの構築を待つだけじゃなく、すべての画像の読み込みも待ってしまうんだ。そうすると、画像を多く含むようなページでは、Ajax の処理がいつまでたってもはじまらない、なんてことが起こって、これは、あんまり嬉しくない。
解決策: onDOMContentLoaded とクロスブラウザな実装
ブラウザごとにさまざまな解決策がある。
たとえば、Firefox など Mozilla 系のブラウザでは onDOMContentLoaded というイベントがあって、これはそのものずばり、DOM ツリーが読み込み完了したときに通知してくれるイベントだ。そして、Safari では document.readyState が、IE では defer 属性を有効にした script 要素の読み込みが利用できる(このへんの詳細は Dean Edwards: The window.onload Problem - Solved! に詳しい)。
また、mootools には window.addEvent('domready', ...)、JQuery には同様に、$(document).ready() というクロスブラウザな実装が用意されている。嬉しいことに、prototype.js にも近いうちに同様の機能を取り込もう、という動きがあるようだ。
- #5414 (PATCH) Faster onload for Event.onload
- Changeset 6596: Support for "DOMContentLoaded" event handling (prototype.js event branch)
今回つくった domready.js は mootools の実装を基にしているが、だいたいどれも同じような実装みたいだ。
5 Comments
09:28
河野
ご丁寧なご回答いただきまして、本当にありがとうございます。
なるほど、そういう理由や経緯があったのですね。
おっしゃるようにJQueryなどでも良いのですが、一瞬「通るだけ」のような、すごく簡易なページがありまして、わざわざライブラリを読み込ませるより、こちらで配布していただいている軽量なスクリプトが良いと思った次第です。
判ってみれば納得なのですが、ナゾのログに少々悩み続けてしまいまして…(苦笑)
原因がスクリプトであることですら、時間を要してしまいました。
もしかしたら同じ状況の人もいらっしゃるかもしれませんので、不肖ながら、御教授いただいたdoScrollを使って書き換えてみたソースを投稿させていただきます。
といっても、単にオリジナルの118~122行を下記に置き換えただけですが。
Event.domReady.timer = setInterval(function() {
try {
document.documentElement.doScroll("left");
} catch (e) {
return;
}
Event.domReady.callback();
}, 50);
15:03
Takanori Ishikawa
>河野さん
コメントありがとうございます。
javascript:void(0) の件ですが、これは HTTPS で javascript:void(0) だと「安全でない」という警告を出すブラウザがあるから、という経緯のようです(ただ、ご指摘のようにサーバにアクセスしてしまう(ブラウザもある)という問題も報告されています)。なので、「空のファイルを用意して読ませる」という対策でも大丈夫なはずです(すべてのブラウザでアクセスが発生してしまいますが...)。
なお、最近の JavaScript ライブラリでは document.documentElement.doScroll を使うテクニックが用いられているようです(参考: http://javascript.nwbox.com/IEContentLoaded/ )。domready.js の実装はだいぶ古くなってしまったので、できれば JQuery や prototype.js といった JavaScript ライブラリを使われることをおすすめします。
05:41
河野
こんにちは。いつも大変参考にさせていただいております。
素朴な疑問なのですが、
IEの場合のscriptタグで、ページがHTTPSならsrc属性を'://0'にするのは、何のためですか?
':'というファイルを読もうとしてサーバーログにNot Foundが大量に記録され、少し気になったもので。
HTTPSでも'javascript:void(0)'にしたり、あるいは空のファイルを用意して読ませる、などに変更しては問題がありますでしょうか。
もしよろしければ、御教授お願いいたします。
12:21
juce6ox
IE/DOMLoad : behavior expression
IEの独自実装による document.write を使わない DOMロード の検知方法を考えました。
CSSのbehaviorとexpressionを使います。
... document.documentElement.style.setExpression('behavior', 'document.documentElement.polli...
10:03
AUSGANG SOFT
DOMContentLoadedとGreasemonkey
今ごろ、まるごとJavaScript & Ajax ! Vol.1を読ん...