Pure JavaScript equivalent of jQuery's $.ready() - how to call a function when the page/DOM is ready for it
好吧,这可能只是一个愚蠢的问题,尽管我相信有很多人不时地问同样的问题。我,我只想对这两种方式都百分之百地肯定。有了jquery,我们都知道
1 | $('document').ready(function(){}); |
但是,假设我想运行一个用标准JavaScript编写的函数,而没有库支持它,并且我想在页面准备好处理它时立即启动一个函数。解决这个问题的正确方法是什么?
我知道我能做到:
1 | window.onload="myFunction()"; |
…或者我可以使用
1 | <body onloadx="myFunction()"> |
…或者我甚至可以尝试在页面的底部搜索所有内容,但结尾的
1 2 | <script type="text/javascript"> myFunction(); |
什么是跨浏览器(旧的/新的)兼容方法,以jquery的
在没有框架的情况下,要做的最简单的事情就是在主体的末尾对代码进行调用,以实现跨浏览器的兼容性。这比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <html> <head> </head> <body> Your HTML here // self executing function here (function() { // your page initialization code here // the DOM will be available here })(); </body> </html> |
如果您真的不想这样做,并且您需要跨浏览器兼容性,并且不想等待
为了让您了解jquery的作用(它将在放置脚本标记的任何位置工作)。
如果支持,它将尝试以下标准:
1 | document.addEventListener('DOMContentLoaded', fn, false); |
回退到:
1 | window.addEventListener('load', fn, false ) |
或者对于旧版本的IE,它使用:
1 | document.attachEvent("onreadystatechange", fn); |
回退到:
1 | window.attachEvent("onload", fn); |
而且,在IE代码路径中有一些我不太明白的解决方法,但它看起来与框架有关。
这里是jquery的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | (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
用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 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); |
此测试已在:
1 2 3 4 5 6 7 | 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/
以下是其工作原理的摘要:
在
如果在文档准备就绪后调用
我想在这里介绍一些可能的方法,以及在所有浏览器中都可以使用的纯JavaScript技巧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 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 like r(function(){ alert('DOM Ready!'); }); |
这里的技巧,正如原作者所解释的,是我们正在检查document.readystate属性。如果它包含字符串
这是在所有浏览器中都可以使用的技巧的JSfiddle。
感谢家教杂志在他们的书中包含了这一点。
如果您在不使用jquery的情况下使用普通的JavaScript,则必须使用(Internet Explorer 9或更高版本):
1 2 3 | document.addEventListener("DOMContentLoaded", function(event) { // Your code to run since DOM is loaded and ready }); |
以上等同于jquery
1 2 3 | $(document).ready(function() { console.log("Ready!"); }); |
它也可以像这样写得很短,jquery甚至会在就绪之后运行。
1 2 3 | $(function() { console.log("ready!"); }); |
不要与以下内容混淆(这并不意味着要准备好DOM):
不要使用这样一个自动执行的生命:
1 2 3 4 5 6 | Example: (function() { // Your page initialization code here - WRONG // The DOM will be available here - WRONG })(); |
这个生命不会等待你的DOM加载。(我甚至在谈论最新版本的Chrome浏览器!)
在IE9和最新的Firefox和Chrome中测试,也在IE8中支持。
1 2 3 4 5 6 7 8 | document.onreadystatechange = function () { var state = document.readyState; if (state == 'interactive') { init(); } else if (state == 'complete') { initOnCompleteLoad(); } }?; |
示例:http://jsfiddle.net/electricivisions/jack/
更新-可重用版本
我刚刚开发了以下内容。它相当于jquery或dom ready,没有向后兼容性。可能还需要进一步完善。在最新版本的Chrome、Firefox和IE(10/11)中测试过,应该可以在老版本的浏览器中使用。如果发现任何问题,我会更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; |
用途:
1 2 3 | ready(function () { // your code here }); |
它是为处理JS的异步加载而编写的,但是您可能希望先同步加载此脚本,除非您正在缩小。我发现它在开发中很有用。
现代浏览器还支持脚本的异步加载,这进一步增强了体验。支持异步意味着可以同时下载多个脚本,同时仍然呈现页面。当依赖于异步加载的其他脚本或使用一个小型化器或类似browserify的东西来处理依赖项时,只需当心。
Hubspot的好人有一种资源,在那里你可以找到纯JavaScript方法来实现许多jQuery的优点,包括
http://youmighnotneedjquery.com/准备好了
1 2 3 4 5 6 7 8 9 10 11 12 | 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(); }); } } |
内联用法示例:
1 | ready(function() { alert('hello'); }); |
您的方法(将脚本放在结束body标记之前)
1 2 3 4 | myFunction() </body> </html> |
是支持新老浏览器的可靠方法。
我不太确定你在问什么,但也许这可以帮助:
1 2 3 4 | window.onload = function(){ // Code. . . } |
或:
1 2 3 4 5 6 | window.onload = main; function main(){ // Code. . . } |
准备好
1 | function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();} |
类使用
1 2 3 | ready(function(){ //some code }); |
用于自调用代码
1 2 3 4 5 6 7 | (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+
这里有一个清理,非eval使用版本的ram swaroop的"在所有浏览器中工作"各种各样——在所有浏览器中工作!
1 2 3 4 5 6 7 8 9 10 | function onReady(yourMethod) { var readyStateCheckInterval = setInterval(function() { if (document && document.readyState === 'complete') { // Or 'interactive' clearInterval(readyStateCheckInterval); yourMethod(); } }, 10); } // use like onReady(function() { alert('hello'); } ); |
不过,它确实要等待额外的10毫秒才能运行,所以这里有一个更复杂的方法,不应该:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 like onReady(function() { alert('hello'); } ); // Or onReady(functionName); |
另请参见如何在没有框架的情况下检查DOM是否就绪?.
似乎你应该只使用jquery-min