在没有一个可以为你完成所有跨浏览器兼容性的框架的情况下,最简单的方法就是在body结束时调用你的代码。这比使用onload处理程序更快,因为它只等待DOM准备就绪,而不是等待所有图像加载完成。并且,这适用于每个浏览器。
<!doctype html>
<html>
<head>
</head>
<body>
Your HTML here
<script>
(function() {
})();
</script>
</body>
</html>
对于现代浏览器(IE9及以上版本,以及任何版本的Chrome、Firefox或Safari),如果你想要实现类似jQuery的$(document).ready()
方法,可以在任何位置调用而不必担心调用脚本所在的位置,只需使用以下代码:
function docReady(fn) {
if (document.readyState === "complete" || document.readyState === "interactive") {
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
使用方法:
docReady(function() {
});
如果你需要完全的跨浏览器兼容性(包括旧版本的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) {
funcName = funcName || "docReady";
baseObj = baseObj || window;
var readyList = [];
var readyFired = false;
var readyEventHandlersInstalled = false;
function ready() {
if (!readyFired) {
readyFired = true;
for (var i = 0; i < readyList.length; i++) {
readyList[i].fn.call(window, readyList[i].ctx);
}
readyList = [];
}
}
function readyStateChange() {
if ( document.readyState === "complete" ) {
ready();
}
}
baseObj[funcName] = function(callback, context) {
if (typeof callback !== "function") {
throw new TypeError("callback for docReady(fn) must be a function");
}
if (readyFired) {
setTimeout(function() {callback(context);}, 1);
return;
} else {
readyList.push({fn: callback, ctx: context});
}
if (document.readyState === "complete") {
setTimeout(ready, 1);
} else if (!readyEventHandlersInstalled) {
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", ready, false);
window.addEventListener("load", ready, false);
} else {
document.attachEvent("onreadystatechange", readyStateChange);
window.attachEvent("onload", ready);
}
readyEventHandlersInstalled = true;
}
}
})("docReady", window);
代码的最新版本已经在GitHub上公开共享,网址为https://github.com/jfriend00/docReady
用法:
docReady(fn);
docReady(function() {
});
docReady(fn, context);
docReady(function(context) {
}, 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
实现和测试环境: http://jsfiddle.net/jfriend00/YfD3C/
以下是其工作原理的概述:
- 创建一个IIFE(立即调用函数表达式),以便我们可以有非公共状态变量。
- 声明一个公共函数
docReady(fn, context)
- 当调用
docReady(fn, context)
时,检查准备好的处理程序是否已经触发。如果是这样,则使用setTimeout(fn, 1)
调度新添加的回调在此JS线程完成后立即触发。
- 如果还没有触发准备好的处理程序,则将此新回调添加到稍后要调用的所有回调列表中。
- 检查文档是否已准备就绪。如果是这样,则执行所有准备好的处理程序。
- 如果我们还没有安装事件侦听器来知道文档何时准备就绪,则现在安装它们。
- 如果
document.addEventListener
存在,则为"DOMContentLoaded"
和"load"
事件使用.addEventListener()
安装事件处理程序。 "Load"是安全备份事件,不应该需要。
- 如果
document.addEventListener
不存在,则使用.attachEvent()
安装"onreadystatechange"
和"onload"
事件的事件处理程序。
- 在
onreadystatechange
事件中,检查document.readyState === "complete"
是否为真,如果是,则调用一个函数来触发所有准备好的处理程序。
- 在所有其他事件处理程序中,调用一个函数以触发所有准备好的处理程序。
- 在用于调用所有就绪处理程序的函数中,检查状态变量,以查看我们是否已经触发。如果是这样,则不执行任何操作。如果我们尚未被调用,则循环遍历就绪函数数组,并按照添加的顺序调用每个函数。设置标志以指示这些都已经调用,因此它们永远不会再次执行。
- 清除函数数组,以便可以释放它们可能正在使用的任何闭包。
使用docReady()
注册的处理程序保证按照它们注册的顺序触发。
如果您在文档已经准备好后调用docReady(fn)
,则将使用setTimeout(fn, 1)
安排回调以在当前执行线程完成后立即执行。这允许调用代码始终假定它们是异步回调,稍后将被调用,即使稍后就是JS当前线程完成时,并保留调用顺序。