Vanilla JavaScript相当于jQuery的$. read()-当页面/DOM准备好时如何调用函数

使用jQuery,我们都知道美妙的.ready()函数:

$('document').ready(function(){});

但是,假设我想运行一个用标准JavaScript编写的函数,没有库支持它,并且我想在页面准备好处理它时立即启动一个函数。

我知道我能做到:

window.onload="myFunction()";

或者我可以使用body标签:

<body onload="myFunction()">

或者我甚至可以在页面底部尝试所有内容,但结尾bodyhtml标记如下:

<script type="text/javascript">myFunction();</script>

什么是跨浏览器(旧/新)兼容的方法,以jQuery$.ready()的方式发布一个或多个函数?

2112127 次浏览

document.ondomcontentready=function(){}应该可以做到这一点,但它没有完全的浏览器兼容性。

看起来你应该只使用jQuery min

您的方法(将脚本放置在结束主体标记之前)

<script>myFunction()</script></body></html>

是支持新旧浏览器的可靠方法。

在没有一个框架为你做所有跨浏览器兼容性的情况下,最简单的做法就是在主体的末尾调用你的代码。这比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),如果您希望能够实现像$(document).ready()这样的jQuery方法,您可以从任何地方调用(而不必担心调用脚本的位置),您可以使用如下内容:

function docReady(fn) {// see if DOM is already availableif (document.readyState === "complete" || document.readyState === "interactive") {// call on next available ticksetTimeout(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代码路径中有一些我不太了解的解决方法,但看起来它与框架有关。


这是用纯JavaScript编写的jQuery.ready()的完整替代品:

(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 namespacefuncName = 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 oncefunction ready() {if (!readyFired) {// this must be set to true before we start calling callbacksreadyFired = 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 listreadyList[i].fn.call(window, readyList[i].ctx);}// allow any closures held by these functions to freereadyList = [];}}
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 callbackbaseObj[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 awayif (readyFired) {setTimeout(function() {callback(context);}, 1);return;} else {// add the function and context to the listreadyList.push({fn: callback, ctx: context});}// if document already ready to go, schedule the ready function to runif (document.readyState === "complete") {setTimeout(ready, 1);} else if (!readyEventHandlersInstalled) {// otherwise if we don't have event handlers installed, install themif (document.addEventListener) {// first choice is DOMContentLoaded eventdocument.addEventListener("DOMContentLoaded", ready, false);// backup is window load eventwindow.addEventListener("load", ready, false);} else {// must be IEdocument.attachEvent("onreadystatechange", readyStateChange);window.attachEvent("onload", ready);}readyEventHandlersInstalled = true;}}})("docReady", window);

最新版本的代码在GitHub上公开共享https://github.com/jfriend00/docReady

用法:

// pass a function referencedocReady(fn);
// use an anonymous functiondocReady(function() {// code here});
// pass a function reference and a context// the context will be passed to the function as the first argumentdocReady(fn, context);
// use an anonymous function with a contextdocReady(function(context) {// code here that can use the context argument that was passed to docReady}, ctx);

这已经在以下方面进行了测试:

IE6 and upFirefox 3.6 and upChrome 14 and upSafari 5.1 and upOpera 11.6 and upMultiple iOS devicesMultiple Android devices

工作实施和测试平台:http://jsfiddle.net/jfriend00/YfD3C/


以下是它如何工作的摘要:

  1. 创建一个IIFE(立即调用的函数表达式),这样我们就可以拥有非公共状态变量。
  2. 声明一个公共函数docReady(fn, context)
  3. 调用docReady(fn, context)时,检查就绪处理程序是否已经触发。如果是这样,只需安排新添加的回调在JS的这个线程以setTimeout(fn, 1)结束后立即触发。
  4. 如果就绪处理程序尚未触发,则将此新回调添加到稍后要调用的回调列表中。
  5. 检查文档是否已准备好。如果是,请执行所有就绪处理程序。
  6. 如果我们还没有安装事件侦听器,还不知道文档何时准备就绪,那么现在就安装它们。
  7. 如果document.addEventListener存在,则使用.addEventListener()"DOMContentLoaded""load"事件安装事件处理程序。“加载”是出于安全考虑的备份事件,不应该需要。
  8. 如果document.addEventListener不存在,则使用.attachEvent()"onreadystatechange""onload"事件安装事件处理程序。
  9. onreadystatechange事件中,检查是否为document.readyState === "complete",如果是,则调用一个函数来触发所有就绪的处理程序。
  10. 在所有其他事件处理程序中,调用一个函数来触发所有就绪的处理程序。
  11. 在调用所有就绪处理程序的函数中,检查一个状态变量以查看我们是否已经触发。如果我们有,什么也不做。如果我们还没有被调用,那么循环遍历就绪函数数组并按照它们添加的顺序调用每个函数。设置一个标志来指示这些都已被调用,因此它们永远不会执行一次以上。
  12. 清除函数数组,以便可以释放他们可能使用的任何闭包。

使用docReady()注册的处理程序保证按照它们注册的顺序被解雇。

如果您在文档已经准备好之后调用docReady(fn),回调将被安排在当前执行线程使用setTimeout(fn, 1)完成后立即执行。这允许调用代码始终假设它们是稍后调用的异步回调,即使稍后是JS当前线程完成并保留调用顺序。

在IE9和最新的Firefox和Chrome中测试,并在IE8中得到支持。

document.onreadystatechange = function () {var state = document.readyState;if (state == 'interactive') {init();} else if (state == 'complete') {initOnCompleteLoad();}}​;

示例:http://jsfiddle.net/electricvisions/Jacck/

更新-可重用版本

我刚刚开发了以下内容。它相当简单,相当于jQuery或Dom就绪,没有向后兼容性。它可能需要进一步改进。在最新版本的Chrome、Firefox和IE(10/11)中测试,应该可以在评论中的旧浏览器中工作。如果我发现任何问题,我会更新。

window.readyHandlers = [];window.ready = function ready(handler) {window.readyHandlers.push(handler);handleState();};
window.handleState = function handleState () {if (['interactive', 'complete'].indexOf(document.readyState) > -1) {while(window.readyHandlers.length > 0) {(window.readyHandlers.shift())();}}};
document.onreadystatechange = window.handleState;

用法:

ready(function () {// your code here});

它是为了处理JS的异步加载而编写的,但您可能希望先同步加载此脚本,除非您正在缩小。我发现它在开发中很有用。

现代浏览器还支持脚本的异步加载,这进一步增强了体验。对异步的支持意味着可以同时下载多个脚本,同时仍然渲染页面。当依赖于其他异步加载的脚本时,请小心,或者使用迷你器或类似浏览器序列化的东西来处理依赖项。

我想在这里与纯javascript技巧,适用于所有浏览器一起提到一些可能的方法:

// with jQuery$(document).ready(function(){ /* ... */ });
// shorter jQuery version$(function(){ /* ... */ });
// without jQuery (doesn't work in older IEs)document.addEventListener('DOMContentLoaded', function(){// your code goes here}, false);
// and here's the trick (works everywhere)function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}// use liker(function(){alert('DOM Ready!');});

这里的技巧,正如原作者所解释的,是我们检查document.ready国家属性。如果它包含字符串in(如uninitializedloading,前两个DOM就绪状态/5),我们设置超时并再次检查。否则,我们执行传递的函数。

这是jsFiddle的技巧适用于所有浏览器。

感谢Tutorialzine将此包含在他们的书中。

HubSpot的优秀人员有一个资源,您可以在其中找到实现大量jQuery优点的纯Javascript方法-包括ready

http://youmightnotneedjquery.com/#ready

function ready(fn) {if (document.readyState != 'loading'){fn();} else if (document.addEventListener) {document.addEventListener('DOMContentLoaded', fn);} else {document.attachEvent('onreadystatechange', function() {if (document.readyState != 'loading')fn();});}}

示例内联用法:

ready(function() { alert('hello'); });

如果您在没有jQuery的情况下执行香草普通javascript,那么您必须使用(Internet Explorer 9或更高版本):

document.addEventListener("DOMContentLoaded", function(event) {// Your code to run since DOM is loaded and ready});

上面是jQuery.ready的等价物:

$(document).ready(function() {console.log("Ready!");});

它也可以像这样快速编写,jQuery将在就绪后运行发生

$(function() {console.log("ready!");});

不要与下面混淆(这不是DOM就绪):

不要使用像这样的IIFE是自动执行的:

 Example:
(function() {// Your page initialization code here  - WRONG// The DOM will be available here   - WRONG})();

这个IIFE不会等待你的DOM加载。(我甚至在谈论最新版本的Chrome浏览器!)

准备

function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();}

使用like

ready(function(){//some code});

用于自调用代码

(function(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();})(function(){
//Some Code here//DOM is avaliable//var h1s = document.querySelector("h1");
});

支持:IE9+

我不太确定你在问什么,但也许这可以帮助:

window.onload = function(){// Code. . .
}

或:

window.onload = main;
function main(){// Code. . .
}

这是一个清理过的、不使用评估的版本Ram-Swaroop的“适用于所有浏览器”变体——适用于所有浏览器!

function onReady(yourMethod) {var readyStateCheckInterval = setInterval(function() {if (document && document.readyState === 'complete') { // Or 'interactive'clearInterval(readyStateCheckInterval);yourMethod();}}, 10);}// use likeonReady(function() { alert('hello'); } );

但是,它确实需要额外等待10毫秒才能运行,因此这里有一种更复杂的方法不应该:

function onReady(yourMethod) {if (document.readyState === 'complete') { // Or also compare to 'interactive'setTimeout(yourMethod, 1); // Schedule to run immediately}else {readyStateCheckInterval = setInterval(function() {if (document.readyState === 'complete') { // Or also compare to 'interactive'clearInterval(readyStateCheckInterval);yourMethod();}}, 10);}}
// Use likeonReady(function() { alert('hello'); } );
// OronReady(functionName);

另见如何在没有框架的情况下检查DOM是否准备就绪?