さて、これは単なる愚問かもしれませんが、同じような質問をしている人はたくさんいると思います。私は、どちらにしても100%の確信を持ちたいと思っています。jQueryでは、私たちは皆、素晴らしい
$('document').ready(function(){});
しかし、標準のJavaScriptで書かれた関数を、ライブラリを使わずに実行したいとします。どのようにアプローチするのが適切なのでしょうか?
できることはわかっています。
window.onload="myFunction()";
...または、body
タグを使うこともできます。
<body onload="myFunction()">
...あるいは、ページの一番下で、すべてのものの後に、最後の body
または html
タグを使って、次のように試してみることもできます。
<script type="text/javascript">
myFunction();
</script>
jQuery'の$.ready()
のように、1つまたは複数の関数を発行するクロスブラウザ(新旧)に準拠した方法はありますか?
すべてのクロスブラウザ対応をしてくれるフレームワークがない場合の最も簡単な方法は、ボディの最後にコードへの呼び出しを置くことです。 これは、すべての画像がロードされるのではなく、DOMが準備されるのを待つだけなので、onload
ハンドラよりも実行が速いです。 また、これはどのブラウザでも動作します。
<!doctype html>
<html>
<head>
</head>
<body>
Your HTML here
<script>
// self executing function here
(function() {
// your page initialization code here
// the DOM will be available here
})();
</script>
</body>
</html>
モダンブラウザ(IE9以降、Chrome、Firefox、Safariのいずれかのバージョン)では、どこからでも呼べるjQueryのような$(document).ready()
メソッドを実装したい場合(呼び出しスクリプトの位置を気にせずに)、次のようにすればよいでしょう。
function docReady(fn) {
// see if DOM is already available
if (document.readyState === "complete" || document.readyState === "interactive") {
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
使い方。
docReady(function() {
// DOM is loaded and ready for manipulation here
});
完全なクロスブラウザ互換性(古いバージョンのIEを含む)が必要で、window.onload
を待ちたくない場合は、jQueryのようなフレームワークがどのように$(document).ready()
メソッドを実装しているかを見てみるべきでしょう。 ブラウザの機能にもよりますが、かなり複雑です。
jQueryが何をしているかを少し紹介しましょう(scriptタグがどこに置かれていても動作します)。
サポートされていれば、標準的なものを試します。
document.addEventListener('DOMContentLoaded', fn, false);
にフォールバックします。
window.addEventListener('load', fn, false )
を使用し、古いバージョンのIEでは
document.attachEvent("onreadystatechange", fn);
にフォールバックします。
window.attachEvent("onload", fn);
また、IEのコードパスには、よくわからない回避策がありますが、フレームに関係しているようです。
jQuery'の.ready()
の完全な代用として、プレーンなjavascriptで書かれたものです。
(function(funcName, baseObj) {
// The public function name defaults to window.docReady
// but you can pass in your own object and own function name and those will be used
// if you want to put them in a different namespace
funcName = funcName || "docReady";
baseObj = baseObj || window;
var readyList = [];
var readyFired = false;
var readyEventHandlersInstalled = false;
// call this when the document is ready
// this function protects itself against being called more than once
function ready() {
if (!readyFired) {
// this must be set to true before we start calling callbacks
readyFired = true;
for (var i = 0; i < readyList.length; i++) {
// if a callback here happens to add new ready handlers,
// the docReady() function will see that it already fired
// and will schedule the callback to run right after
// this event loop finishes so all handlers will still execute
// in order and no new ones will be added to the readyList
// while we are processing the list
readyList[i].fn.call(window, readyList[i].ctx);
}
// allow any closures held by these functions to free
readyList = [];
}
}
function readyStateChange() {
if ( document.readyState === "complete" ) {
ready();
}
}
// This is the one public interface
// docReady(fn, context);
// the context argument is optional - if present, it will be passed
// as an argument to the callback
baseObj[funcName] = function(callback, context) {
if (typeof callback !== "function") {
throw new TypeError("callback for docReady(fn) must be a function");
}
// if ready has already fired, then just schedule the callback
// to fire asynchronously, but right away
if (readyFired) {
setTimeout(function() {callback(context);}, 1);
return;
} else {
// add the function and context to the list
readyList.push({fn: callback, ctx: context});
}
// if document already ready to go, schedule the ready function to run
if (document.readyState === "complete") {
setTimeout(ready, 1);
} else if (!readyEventHandlersInstalled) {
// otherwise if we don't have event handlers installed, install them
if (document.addEventListener) {
// first choice is DOMContentLoaded event
document.addEventListener("DOMContentLoaded", ready, false);
// backup is window load event
window.addEventListener("load", ready, false);
} else {
// must be IE
document.attachEvent("onreadystatechange", readyStateChange);
window.attachEvent("onload", ready);
}
readyEventHandlersInstalled = true;
}
}
})("docReady", window);
このコードの最新版は、GitHub(https://github.com/jfriend00/docReady)で公開されています。
使用方法
// pass a function reference
docReady(fn);
// use an anonymous function
docReady(function() {
// code here
});
// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);
// use an anonymous function with a context
docReady(function(context) {
// code here that can use the context argument that was passed to docReady
}, ctx);
でテストされています。
言語: lang-none -->
IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices
作業用の実装とテストベッド:
以下は、その仕組みの概要です。
docReady(fn, context)
を宣言する。docReady(fn, context)
が呼ばれたとき、readyハンドラがすでに起動しているかどうかをチェックする。 もしそうであれば,新たに追加したコールバックが,このJSのスレッドが終了した直後に発火するように,setTimeout(fn, 1)
でスケジュールします.document.addEventListener
が存在する場合は、"DOMContentLoaded"
と "load"
の両方のイベントに対して .addEventListener()
を使用してイベントハンドラをインストールします。 なお、"load"は安全のためのバックアップイベントであり、必要ありません。document.addEventListener
が存在しない場合は、.attachEvent()
を使用して、"onreadystatechange"
と "onload"
イベント用のイベントハンドラをインストールします。onreadystatechange
イベントでは、document.readyState === "complete"
であるかどうかを確認し、もしそうであれば、すべての ready ハンドラを起動する関数を呼び出します。
10.他のすべてのイベントハンドラで、すべてのレディハンドラを起動する関数を呼び出します。
11.11. すべてのレディハンドラを呼び出す関数の中で、ステート変数をチェックして、すでに発射されたかどうかを確認します。 発火していれば何もしません。 まだ呼ばれていない場合は、ready関数の配列をループして、追加された順に各関数を呼び出します。 すべての関数が呼び出されたことを示すフラグを設定して、2回以上実行されないようにします。docReady()`で登録されたハンドラは、登録された順に実行されることが保証されています。
ドキュメントの準備が完了した後に docReady(fn)
を呼び出した場合、コールバックは setTimeout(fn, 1)
を使って現在の実行スレッドが完了した時点で実行されるようにスケジュールされます。 これにより、呼び出し側のコードは、現在のスレッドの実行が終了すると同時に呼び出される非同期コールバックであると常に仮定することができ、呼び出し順が保持されます。
あなたの方法(スクリプトをbodyタグの前に置く)
<script>
myFunction()
</script>
</body>
</html>
は、新旧のブラウザに対応するための確実な方法です。