我有一个使用$(document).ready的脚本,但它不使用jQuery中的任何其他内容。我想通过删除jQuery依赖项来减轻它。
如何在不使用jQuery的情况下实现我自己的$(document).ready功能?我知道,使用window.onload将不同,因为window.onlead在加载所有图像、帧等后启动。
我有一个使用$(document).ready的脚本,但它不使用jQuery中的任何其他内容。我想通过删除jQuery依赖项来减轻它。
如何在不使用jQuery的情况下实现我自己的$(document).ready功能?我知道,使用window.onload将不同,因为window.onlead在加载所有图像、帧等后启动。
当前回答
比较
这里(在下面的片段中)是所选择的可用浏览器“内置”方法及其执行顺序的比较。评论
任何现代浏览器都不支持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('<','<;').replace('>','>;')+'<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>
其他回答
这是我使用的,它很快,涵盖了我认为的所有基础;适用于除IE<9以外的所有情况。
(() => { function fn() {
// "On document ready" commands:
console.log(document.readyState);
};
if (document.readyState != 'loading') {fn()}
else {document.addEventListener('DOMContentLoaded', fn)}
})();
这似乎适用于所有情况:
如果DOM已经就绪(如果DOM不是“加载”,而是“交互式”或“完成”),则立即激发如果DOM仍在加载,它将在DOM可用(交互式)。
DOMContentLoaded事件在IE9和其他所有版本中都可用,所以我个人认为使用它是可以的。如果您没有将代码从ES2015传输到ES5,请将箭头函数声明重写为常规匿名函数。
如果您想等到加载所有资产、显示所有图像等,请改用window.onload。
如果您不必支持非常旧的浏览器,即使在外部脚本加载了异步属性时,也可以使用以下方法:
HTMLDocument.prototype.ready = new Promise(function(resolve) {
if(document.readyState != "loading")
resolve();
else
document.addEventListener("DOMContentLoaded", function() {
resolve();
});
});
document.ready.then(function() {
console.log("document.ready");
});
我们发现了一个快速而肮脏的跨浏览器实现,它可以用最少的实现实现大多数简单情况:
window.onReady = function onReady(fn){
document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};
这个解决方案怎么样?
// other onload attached earlier
window.onload=function() {
alert('test');
};
tmpPreviousFunction=window.onload ? window.onload : null;
// our onload function
window.onload=function() {
alert('another message');
// execute previous one
if (tmpPreviousFunction) tmpPreviousFunction();
};
最小且100%工作
我已经从PlainJS中选择了答案,它对我来说很好。它扩展了DOMContentLoaded,因此它可以在所有浏览器中被接受。
此函数等效于jQuery的$(document).ready()方法:
document.addEventListener('DOMContentLoaded', function(){
// do something
});
然而,与jQuery不同的是,这段代码只能在现代浏览器中正常运行(IE>8),如果在插入此脚本时(例如通过Ajax)已经呈现了文档,则无法正常运行。因此,我们需要稍微扩展一下:
function run() {
// do something
}
// in case the document is already rendered
if (document.readyState!='loading') run();
// modern browsers
else if (document.addEventListener)
document.addEventListener('DOMContentLoaded', run);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') run();
});
这基本上涵盖了所有的可能性,是jQuery助手的可行替代品。