jQuery的$ .ready()的纯JavaScript等价物 - 如何在页面/ DOM准备好时调用该函数 [英] Pure JavaScript equivalent of jQuery's $.ready() - how to call a function when the page/DOM is ready for it

查看:117
本文介绍了jQuery的$ .ready()的纯JavaScript等价物 - 如何在页面/ DOM准备好时调用该函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,这可能只是一个愚蠢的问题,但我确定有很多其他人不时地提出同样的问题。我,我只是想100%肯定它的方式。有了jQuery,我们都知道了美妙的

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

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



我知道我可以这样做:

 的window.onload = myFunction的(); 

...或者我可以使用主体 tag:

 < body onload =myFunction()> 

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

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

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

解决方案

在没有为您提供所有跨浏览器兼容性的框架的情况下要做的事情就是在本体的末尾调用您的代码。执行速度比 onload 处理程序快,因为它只等待DOM准备就绪,而不是等待所有图像加载。而且,这在每个浏览器中都可行。

 < html> 
< head>
< / head>
< body>
您的HTML在这里

< script>
//自动执行函数
(函数(){
//您的页面初始化代码
// DOM将在此处可用

})();
< / script>
< / body>
< / html>

如果您真的不想这样做,并且您需要跨浏览器兼容性,不想等待 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){
//公共函数名默认为window.docReady
//但是你可以传递你自己的对象和自己的函数名,那些将被使用
//如果你想把它们放入不同的命名空间
funcName = funcName ||docReady;
baseObj = baseObj || window;
var readyList = [];
var readyFired = false;
var readyEventHandlersInstalled = false;

//在文档准备就绪时调用
//此函数保护自己不被多次调用
函数ready(){
if(!readyFired){
//必须设置为在我们开始调用回调之前为true
readyFired = true;
for(var i = 0; i< readyList.length; i ++){
//如果在这里发生回调会添加新的就绪处理程序,
// docReady()函数将看到它已经触发了
//并且会安排回调在
之后运行//这个事件循环结束后,所有的处理程序仍然会按顺序执行$ ​​b $ b //并且不会有新的添加到readyList
//我们正在处理列表
readyList [i] .fn.call(window,readyList [i] .ctx);
}
//允许这些函数持有的任何闭包释放
readyList = [];



函数readyStateChange(){
if(document.readyState ===complete){
ready();
}
}

//这是一个公共接口
// docReady(fn,context);
//上下文参数是可选的 - 如果存在,它将通过
//作为参数传递给回调函数
aseObj [funcName] = function(callback,context){$ b $如果(typeof callback!==function){
throw new TypeError(docReady(fn)的回调函数必须是函数);
}
//如果ready已经被触发,那么只需安排回调
//来异步触发,但是马上
if(readyFired){
setTimeout( function(){callback(context);},1);
return;
} else {
//将函数和上下文添加到列表
readyList.push({fn:callback,ctx:context});
}
//如果文档已经准备好了,安排ready函数运行
if(document.readyState ===complete){
setTimeout(ready,1 );
} else if(!readyEventHandlersInstalled){
//否则,如果我们没有安装事件处理程序,请安装它们
if(document.addEventListener){
//第一个选项是DOMContentLoaded事件
document.addEventListener(DOMContentLoaded,ready,false);
//备份是窗口加载事件
window.addEventListener(load,ready,false);
} else {
//必须是IE
document.attachEvent(onreadystatechange,readyStateChange);
window.attachEvent(onload,ready);
}
readyEventHandlersInstalled = true;
}
}
})(docReady,window);

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



用法:

  //传递函数引用
docReady(fn);

//使用匿名函数
docReady(function(){
// code here
));

//传递函数引用和上下文
//上下文将作为第一个参数传递给函数
docReady(fn,context);

//使用带上下文的匿名函数
docReady(函数(上下文){
//代码可以使用传递给docReady $ b $的上下文参数b},ctx);






这已经过测试:

IE6及以上
Firefox 3.6及以上
Chrome 14及以上
Safari 5.1及以上
Opera 11.6及以上
多台iOS设备
多台Android设备

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






下面是它的工作原理摘要:


  1. 立即创建一个 IIFE 调用函数表达式),所以我们可以拥有非公共的状态变量。
  2. 声明一个公共函数 docReady(fn,context)

  3. 当调用 docReady(fn,context)时,检查ready handler是否已经被触发。如果是这样,只需在JS的这个线程完成 setTimeout(fn,1)之后立即调用新添加的回调。

  4. 如果ready处理程序尚未触发,则将此新回调添加到稍后调用的回调列表中。
  5. 检查文档是否已准备就绪。如果是,请执行所有准备就绪的处理程序。

  6. 如果我们尚未安装事件侦听器,但尚未知道文档何时准备就绪,请立即安装它们。

  7. 如果存在 document.addEventListener ,则使用 .addEventListener()DOMContentLoaded和load events。如果 document.addEventListener 不存在,那么这个加载是一个安全备份事件,不应该被需要。 使用 .attachEvent()onreadystatechangeonload code> events。

  8. onreadystatechange 事件中,检查 document.readyState ===complete如果是这样,调用一个函数来触发所有就绪处理程序。

  9. 在所有其他事件处理程序中,调用一个函数来触发所有就绪处理程序。

  10. 在调用所有就绪处理程序的函数中,检查一个状态变量以查看我们是否已经开启了。如果我们有,什么也不做。如果我们还没有被调用,然后遍历已准备函数的数组,并按照它们添加的顺序调用每个函数。设置一个标志来表明这些全部被调用,所以它们永远不会被执行多次。

  11. 清除函数数组,以便释放它们可能使用的闭包。

通过 docReady()注册的处理程序保证按照它们注册的顺序被触发。 / p>

如果您在文档已准备好之后调用 docReady(fn),则回调将被安排为尽快执行因为当前的执行线程使用 setTimeout(fn,1)完成。这允许调用代码始终假定它们是稍后调用的异步回调函数,即使稍后会在JS的当前线程结束并且保留调用顺序时也是如此。


Okay, this might just be a silly question, though I'm sure there are plenty of other people asking the same question from time to time. Me, I just want to make 100% sure about it either way. With jQuery we all know the wonderful

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

However, let's say I want to run a function that is written in standard JavaScript with no library backing it, and that I want to launch a function as soon as the page is ready to handle it. What's the proper way to approach this?

I know I can do:

window.onload="myFunction()";

...or I can use the body tag:

<body onload="myFunction()">

...or I can even try at the bottom of the page after everything, but the end body or html tag like:

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

What is a cross-browser(old/new)-compliant method of issuing one or more functions in a manner like jQuery's $.ready()?

解决方案

The simplest thing to do in the absence of a framework that does all the cross-browser compatibility for you is to just put a call to your code at the end of the body. This is faster to execute than an onload handler because this waits only for the DOM to be ready, not for all images to load. And, this works in every browser.

<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>

If you really don't want to do it this way and you need cross browser compatibility and you don't want to wait for window.onload, then you probably should go look at how a framework like jQuery implements it's $(document).ready() method. It's fairly involved depending upon the capabilities of the browser.

To give you a little idea what jQuery does (which will work wherever the script tag is placed).

If supported, it tries the standard:

document.addEventListener('DOMContentLoaded', fn, false);

with a fallback to:

window.addEventListener('load', fn, false )

or for older versions of IE, it uses:

document.attachEvent("onreadystatechange", fn);

with a fallback to:

window.attachEvent("onload", fn);

And, there are some work-arounds in the IE code path that I don't quite follow, but it looks like it has something to do with frames.


Here is a full substitute for jQuery's .ready() written in plain 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);

The latest version of the code is shared publicly on GitHub at https://github.com/jfriend00/docReady

Usage:

// 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);


This has been tested in:

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

Working implementation and test bed: http://jsfiddle.net/jfriend00/YfD3C/


Here's a summary of how it works:

  1. Create an IIFE (immediately invoked function expression) so we can have non-public state variables.
  2. Declare a public function docReady(fn, context)
  3. When docReady(fn, context) is called, check if the ready handler has already fired. If so, just schedule the newly added callback to fire right after this thread of JS finishes with setTimeout(fn, 1).
  4. If the ready handler has not already fired, then add this new callback to the list of callbacks to be called later.
  5. Check if the document is already ready. If so, execute all ready handlers.
  6. If we haven't installed event listeners yet to know when the document becomes ready, then install them now.
  7. If document.addEventListener exists, then install event handlers using .addEventListener() for both "DOMContentLoaded" and "load" events. The "load" is a backup event for safety and should not be needed.
  8. If document.addEventListener doesn't exist, then install event handlers using .attachEvent() for "onreadystatechange" and "onload" events.
  9. In the onreadystatechange event, check to see if the document.readyState === "complete" and if so, call a function to fire all the ready handlers.
  10. In all the other event handlers, call a function to fire all the ready handlers.
  11. In the function to call all the ready handlers, check a state variable to see if we've already fired. If we have, do nothing. If we haven't yet been called, then loop through the array of ready functions and call each one in the order they were added. Set a flag to indicate these have all been called so they are never executed more than once.
  12. Clear the function array so any closures they might be using can be freed.

Handlers registered with docReady() are guaranteed to be fired in the order they were registered.

If you call docReady(fn) after the document is already ready, the callback will be scheduled to execute as soon as the current thread of execution completes using setTimeout(fn, 1). This allows the calling code to always assume they are async callbacks that will be called later, even if later is as soon as the current thread of JS finishes and it preserves calling order.

这篇关于jQuery的$ .ready()的纯JavaScript等价物 - 如何在页面/ DOM准备好时调用该函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆