好吧,这可能只是一个愚蠢的问题,虽然我'肯定还有很多人时常问同样的问题。我,我只是想对它进行100%的确认,无论如何。对于jQuery,我们都知道奇妙的
$('document').ready(function(){});
然而,假设我想运行一个用标准的JavaScript编写的函数,没有库的支持,而且我想在页面准备好后立即启动一个函数来处理它。正确的方法是什么?
我知道我可以这样做。
window.onload="myFunction()";
...或者我可以使用body
标签。
<body onload="myFunction()">
...或者我甚至可以尝试在页面底部的所有内容之后,但结尾的body
或html
标签,比如。
<script type="text/javascript">
myFunction();
</script>
什么是符合跨浏览器(旧/新)的方法,以类似jQuery'的$.ready()
的方式发布一个或多个函数?
在没有一个框架为你做所有的跨浏览器兼容性的情况下,最简单的事情就是在正文的最后放一个对你代码的调用。 这比onload
处理程序执行得更快,因为它只等待DOM准备好,而不是等待所有图片加载。 而且,这在每个浏览器中都适用。
<!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的工作(无论脚本标签放在哪里都能发挥作用)。
如果支持,它会尝试标准的。
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);
这已经在以下方面进行了测试。
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 handler是否已经启动。 如果是的话,只需安排新添加的回调在这个JS线程结束后用setTimeout(fn, 1)
启动即可。document.addEventListener
存在,那么使用.addEventListener()
为"DOMContentLoaded"
和"load"
两个事件安装事件处理程序。 `quot;load"是一个安全的备份事件,不应该被需要。document.addEventListener
不存在,则使用.attachEvent()
为"onreadystatechange"
和`"onload"事件安装事件处理程序。onreadystatechange
事件中,检查document.readyState ==="complete"
,如果是,则调用一个函数来启动所有就绪处理程序。
10.在所有其他的事件处理程序中,调用一个函数来启动所有的就绪处理程序。
11.在调用所有就绪处理程序的函数中,检查一个状态变量,看我们是否已经启动了。 如果我们已经启动了,就什么都不要做。 如果我们还没有被调用,那么就循环浏览准备好的函数数组,按照它们被添加的顺序逐一调用。 设置一个标志,表明这些函数都被调用过,这样它们就不会被执行超过一次。用docReady()
注册的处理程序保证按照它们被注册的顺序被触发。
如果你在文档已经准备好后调用docReady(fn)
,回调将被安排在当前执行线程完成后使用setTimeout(fn, 1)
执行。 这使得调用代码总是认为它们是异步回调,将在稍后被调用,即使稍后是在当前JS线程完成后立即被调用,而且它保留了调用顺序。
你的方法(将脚本放在正文标签的结尾之前)。
<script>
myFunction()
</script>
</body>
</html>
是一种支持新旧浏览器的可靠方法。