我有一个使用$(document).ready的脚本,但它不使用jQuery中的任何其他内容。我想通过删除jQuery依赖项来减轻它。

如何在不使用jQuery的情况下实现我自己的$(document).ready功能?我知道,使用window.onload将不同,因为window.onlead在加载所有图像、帧等后启动。


当前回答

此处提供的setTimeout/setInterval解决方案仅在特定情况下有效。

该问题在旧版本的Internet Explorer(最高8版)中尤为突出。

影响这些setTimeout/setInterval解决方案成功的变量有:

1) dynamic or static HTML
2) cached or non cached requests
3) size of the complete HTML document
4) chunked or non chunked transfer encoding

解决此特定问题的原始(原生Javascript)代码如下:

https://github.com/dperini/ContentLoaded
http://javascript.nwbox.com/ContentLoaded (test)

这是jQuery团队构建其实现的代码。

其他回答

对于IE9+:

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

我只使用:

setTimeout(function(){
    //reference/manipulate DOM here
});

而且与上面的答案中的document.addEventListener(“DOMContentLoaded”//等不同,它的工作时间可以追溯到IE9——http://caniuse.com/#search=DOMContentLoaded仅表示最近的IE11。

有趣的是,我在2009年偶然发现了这个setTimeout解决方案:检查DOM的准备是否过度?,我的意思是“使用各种框架的更复杂的方法来检查DOM的就绪性是否过分”。

我对这种技术为什么有效的最好解释是,当使用这样一个setTimeout的脚本到达时,DOM正处于解析过程中,因此setTimeout中的代码的执行会延迟到该操作完成。

穷人的解决方案:

var checkLoad = function() {   
    document.readyState !== "complete" ? setTimeout(checkLoad, 11) : alert("loaded!");   
};  

checkLoad();  

查看Fiddle

添加了这个,我想更好一点,自己的范围,非递归

(function(){
    var tId = setInterval(function() {
        if (document.readyState == "complete") onComplete()
    }, 11);
    function onComplete(){
        clearInterval(tId);    
        alert("loaded!");    
    };
})()

查看Fiddle

值得在Rock Solid addEvent()和http://www.braksator.com/how-to-make-your-own-jquery.

这是网站崩溃时的代码

function addEvent(obj, type, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
        EventCache.add(obj, type, fn);
    }
    else if (obj.attachEvent) {
        obj["e"+type+fn] = fn;
        obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
        obj.attachEvent( "on"+type, obj[type+fn] );
        EventCache.add(obj, type, fn);
    }
    else {
        obj["on"+type] = obj["e"+type+fn];
    }
}

var EventCache = function(){
    var listEvents = [];
    return {
        listEvents : listEvents,
        add : function(node, sEventName, fHandler){
            listEvents.push(arguments);
        },
        flush : function(){
            var i, item;
            for(i = listEvents.length - 1; i >= 0; i = i - 1){
                item = listEvents[i];
                if(item[0].removeEventListener){
                    item[0].removeEventListener(item[1], item[2], item[3]);
                };
                if(item[1].substring(0, 2) != "on"){
                    item[1] = "on" + item[1];
                };
                if(item[0].detachEvent){
                    item[0].detachEvent(item[1], item[2]);
                };
                item[0][item[1]] = null;
            };
        }
    };
}();

// Usage
addEvent(window, 'unload', EventCache.flush);
addEvent(window, 'load', function(){alert("I'm ready");});

比较

这里(在下面的片段中)是所选择的可用浏览器“内置”方法及其执行顺序的比较。评论

任何现代浏览器都不支持document.onload(X)(从不触发事件)如果您使用<body onload=“bodyOnLoad()”>(F),同时使用window.onload(E),则只执行第一个(因为它会覆盖第二个)<body onload=“…”>(F)中给定的事件处理程序由附加的onload函数包装document.onreadystatechange(D)不覆盖document.addEventListener('readystatechange'…)(C)可能是因为类似XYZevent的方法独立于addEventListener队列(允许添加多个侦听器)。在执行这两个处理程序之间可能不会发生任何事情。所有脚本都在控制台中写入时间戳,但也可以访问div的脚本也在主体中写入时间标记(在脚本执行后单击“FullPage”链接查看)。解决方案readystatechange(C,D)由浏览器执行多次,但针对不同的文档状态:loading-文档正在加载(没有在代码段中激发)交互式-文档在DOMContentLoaded之前被解析和激发完成-加载文档和资源,在加载body/window之前激发

<html><head><脚本>//溶液Aconsole.log(`[timestamp:${Date.now()}]A:Head脚本`);//溶液Bdocument.addEventListener(“DOMContentLoaded”,()=>{print(`[时间戳:${Date.now()}]B:DOMContentLoaded`);});//溶液Cdocument.addEventListener('readystatechange',()=>{print(`[时间戳:${Date.now()}]C:就绪状态:${document.ReadyState}`);});//溶液Ddocument.onreadystatechange=s=>{print(`[时间戳:${Date.now()}]D:document.onrreadystatechange就绪状态:${document.ReadyState}`)};//解决方案E(从未执行)window.onload=()=>{print(`E:<body onload=“…”>覆盖此处理程序`);};//溶液F函数体OnLoad(){print(`[timestamp:${Date.now()}]F:<body onload='…'>`);infoAboutOnLoad();//其他信息}//溶液Xdocument.onload=()=>{print(“document.onlead从未启动”)};//助手函数打印(txt){console.log(txt);如果(mydiv)mydiv.innerHTML+=txt.replace('<','&lt;').replace('>','&gt;')+'<br>';}函数infoAboutOnLoad(){console.log(“window.onload(重写后):”,(“”+document.body.onload).replace(/\s+/g,“”));console.log(`body.onload==window.onload-->${document.body.onload==window.onload}`);}console.log(“window.onload(覆盖前):”,(“”+document.body.onload).replace(/\s+/g,“”));</script></head><body onload=“bodyOnLoad()”><div id=“mydiv”></div><!-- 此脚本必须位于<body>-->的底部<脚本>//溶液Gprint(`[timestamp:${Date.now()}]G:<body>底部脚本`);</script></body></html>