我有一个使用的脚本$(document).ready
,但没有使用jQuery中的其他任何脚本。我想通过删除jQuery依赖项来减轻它的负担。
如何在$(document).ready
不使用jQuery的情况下实现自己的功能?我知道使用window.onload
与window.onload
在加载所有图像,框架等之后触发。
我有一个使用的脚本$(document).ready
,但没有使用jQuery中的其他任何脚本。我想通过删除jQuery依赖项来减轻它的负担。
如何在$(document).ready
不使用jQuery的情况下实现自己的功能?我知道使用window.onload
与window.onload
在加载所有图像,框架等之后触发。
Answers:
有一个基于标准的替代品,DOMContentLoaded
超过98%的浏览器都支持它,尽管IE8不支持:
document.addEventListener("DOMContentLoaded", function(event) {
//do work
});
jQuery的本机功能比window.onload复杂得多,如下所示。
function bindReady(){
if ( readyBound ) return;
readyBound = true;
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", function(){
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
jQuery.ready();
}, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", function(){
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", arguments.callee );
jQuery.ready();
}
});
// If IE and not an iframe
// continually check to see if the document is ready
if ( document.documentElement.doScroll && window == window.top ) (function(){
if ( jQuery.isReady ) return;
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch( error ) {
setTimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
jQuery.ready();
})();
}
// A fallback to window.onload, that will always work
jQuery.event.add( window, "load", jQuery.ready );
}
编辑:
function ready(callback){
// in case the document is already rendered
if (document.readyState!='loading') callback();
// modern browsers
else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') callback();
});
}
ready(function(){
// do something
});
取自 https://plainjs.com/javascript/events/running-code-when-the-document-is-ready-15/
另一个很好的domReady函数来自https://stackoverflow.com/a/9899701/175071
由于所接受的答案还远远不够完整,因此我将诸如jQuery.ready()
基于jQuery 1.6.2源的“就绪”功能缝合在一起:
var ready = (function(){
var readyList,
DOMContentLoaded,
class2type = {};
class2type["[object Boolean]"] = "boolean";
class2type["[object Number]"] = "number";
class2type["[object String]"] = "string";
class2type["[object Function]"] = "function";
class2type["[object Array]"] = "array";
class2type["[object Date]"] = "date";
class2type["[object RegExp]"] = "regexp";
class2type["[object Object]"] = "object";
var ReadyObj = {
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
// Hold (or release) the ready event
holdReady: function( hold ) {
if ( hold ) {
ReadyObj.readyWait++;
} else {
ReadyObj.ready( true );
}
},
// Handle when the DOM is ready
ready: function( wait ) {
// Either a released hold or an DOMready/load event and not yet ready
if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
return setTimeout( ReadyObj.ready, 1 );
}
// Remember that the DOM is ready
ReadyObj.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --ReadyObj.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ ReadyObj ] );
// Trigger any bound ready events
//if ( ReadyObj.fn.trigger ) {
// ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
//}
}
},
bindReady: function() {
if ( readyList ) {
return;
}
readyList = ReadyObj._Deferred();
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
return setTimeout( ReadyObj.ready, 1 );
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", ReadyObj.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", DOMContentLoaded );
// A fallback to window.onload, that will always work
window.attachEvent( "onload", ReadyObj.ready );
// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
},
_Deferred: function() {
var // callbacks list
callbacks = [],
// stored [ context , args ]
fired,
// to avoid firing when already doing so
firing,
// flag to know if the deferred has been cancelled
cancelled,
// the deferred itself
deferred = {
// done( f1, f2, ...)
done: function() {
if ( !cancelled ) {
var args = arguments,
i,
length,
elem,
type,
_fired;
if ( fired ) {
_fired = fired;
fired = 0;
}
for ( i = 0, length = args.length; i < length; i++ ) {
elem = args[ i ];
type = ReadyObj.type( elem );
if ( type === "array" ) {
deferred.done.apply( deferred, elem );
} else if ( type === "function" ) {
callbacks.push( elem );
}
}
if ( _fired ) {
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
}
}
return this;
},
// resolve with given context and args
resolveWith: function( context, args ) {
if ( !cancelled && !fired && !firing ) {
// make sure args are available (#8421)
args = args || [];
firing = 1;
try {
while( callbacks[ 0 ] ) {
callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
}
}
finally {
fired = [ context, args ];
firing = 0;
}
}
return this;
},
// resolve with this as context and given arguments
resolve: function() {
deferred.resolveWith( this, arguments );
return this;
},
// Has this deferred been resolved?
isResolved: function() {
return !!( firing || fired );
},
// Cancel
cancel: function() {
cancelled = 1;
callbacks = [];
return this;
}
};
return deferred;
},
type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ Object.prototype.toString.call(obj) ] || "object";
}
}
// The DOM ready check for Internet Explorer
function doScrollCheck() {
if ( ReadyObj.isReady ) {
return;
}
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
// and execute any waiting functions
ReadyObj.ready();
}
// Cleanup functions for the document ready method
if ( document.addEventListener ) {
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
ReadyObj.ready();
};
} else if ( document.attachEvent ) {
DOMContentLoaded = function() {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
ReadyObj.ready();
}
};
}
function ready( fn ) {
// Attach the listeners
ReadyObj.bindReady();
var type = ReadyObj.type( fn );
// Add the callback
readyList.done( fn );//readyList is result of _Deferred()
}
return ready;
})();
如何使用:
<script>
ready(function(){
alert('It works!');
});
ready(function(){
alert('Also works!');
});
</script>
我不确定此代码的功能如何,但在我的表面测试中效果很好。这花费了一段时间,所以我希望您和其他人可以从中受益。
PS .:我建议编译它。
或者,您可以使用http://dustindiaz.com/smallest-domready-ever:
function r(f){/in/.test(document.readyState)?setTimeout(r,9,f):f()}
r(function(){/*code to run*/});
或本机函数(如果您仅需要支持新的浏览器)(与jQuery ready不同,如果在页面加载后添加此功能,则该功能将无法运行)
document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
三种选择:
script
是正文的最后一个标签,则在执行脚本标签之前,DOM已准备就绪就绪状态变更
document.onreadystatechange = function () {
if (document.readyState == "complete") {
// document is ready. Do your stuff here
}
}
资料来源:MDN
DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() {
console.log('document is ready. I can sleep now');
});
有关石器时代的浏览器:
转到jQuery源代码并使用该ready
功能。在那种情况下,您没有解析+执行整个库,而是只执行了很小一部分。
将您的<script>/*JavaScript code*/</script>
权利放在结束 </body>
标记之前。
诚然,这可能不适合每个人的目的,因为它需要更改HTML文件,而不是仅仅在JavaScript文件中做一些事情document.ready
,但是仍然...
</html>
的标签?
穷人的解决方案:
var checkLoad = function() {
document.readyState !== "complete" ? setTimeout(checkLoad, 11) : alert("loaded!");
};
checkLoad();
添加了这一点,我想更好一点,自己的范围,并且非递归
(function(){
var tId = setInterval(function() {
if (document.readyState == "complete") onComplete()
}, 11);
function onComplete(){
clearInterval(tId);
alert("loaded!");
};
})()
setInterval
并完全删除递归。
我用这个:
document.addEventListener("DOMContentLoaded", function(event) {
//Do work
});
注意:这可能仅适用于较新的浏览器,尤其是以下浏览器:http : //caniuse.com/#feat=domcontentloaded
确实,如果您只关心Internet Explorer 9+,那么此代码足以替换jQuery.ready
:
document.addEventListener("DOMContentLoaded", callback);
如果您担心Internet Explorer 6和某些非常奇怪和稀有的浏览器,则可以使用:
domReady: function (callback) {
// Mozilla, Opera and WebKit
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", callback, false);
// If Internet Explorer, the event model is used
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function() {
if (document.readyState === "complete" ) {
callback();
}
});
// A fallback to window.onload, that will always work
} else {
var oldOnload = window.onload;
window.onload = function () {
oldOnload && oldOnload();
callback();
}
}
},
这个问题是很久以前问过的。对于只看到这个问题的任何人,现在都有一个名为“您可能不需要jquery”的网站 按所需的IE支持级别细分了jquery的所有功能,并提供了一些替代的小型库。
根据您可能不需要jQuery的 IE8文档就绪脚本
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();
});
}
'onreadystatechange'
需要而不是document.attachEvent('onload', fn);
我最近在移动网站上使用了它。这是John Resig的“ Pro JavaScript Techniques”的简化版本。这取决于addEvent。
var ready = ( function () {
function ready( f ) {
if( ready.done ) return f();
if( ready.timer ) {
ready.ready.push(f);
} else {
addEvent( window, "load", isDOMReady );
ready.ready = [ f ];
ready.timer = setInterval(isDOMReady, 13);
}
};
function isDOMReady() {
if( ready.done ) return false;
if( document && document.getElementsByTagName && document.getElementById && document.body ) {
clearInterval( ready.timer );
ready.timer = null;
for( var i = 0; i < ready.ready.length; i++ ) {
ready.ready[i]();
}
ready.ready = null;
ready.done = true;
}
}
return ready;
})();
jQuery答案对我来说非常有用。只需一点重构,就可以很好地满足我的需求。我希望它对其他人有帮助。
function onReady ( callback ){
var addListener = document.addEventListener || document.attachEvent,
removeListener = document.removeEventListener || document.detachEvent
eventName = document.addEventListener ? "DOMContentLoaded" : "onreadystatechange"
addListener.call(document, eventName, function(){
removeListener( eventName, arguments.callee, false )
callback()
}, false )
}
removeListener
将需要使用文档作为上下文来调用。removeListener.call(document, ...
这是测试DOM就绪的最小代码段,该代码段可在所有浏览器(甚至是IE 8)上运行:
r(function(){
alert('DOM Ready!');
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
看到这个答案。
只需将其添加到HTML页面的底部...
<script>
Your_Function();
</script>
因为,HTML文档是由上至下解析的。
值得一看的是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");});
DOM准备就绪后,此跨浏览器代码将调用一个函数:
var domReady=function(func){
var scriptText='('+func+')();';
var scriptElement=document.createElement('script');
scriptElement.innerText=scriptText;
document.body.appendChild(scriptElement);
};
运作方式如下:
domReady
调用toString
函数的方法,以获取传入的函数的字符串表示形式,并将其包装在立即调用该函数的表达式中。domReady
创建带有表达式的脚本元素,并将其附加到body
文档的。body
在DOM准备好后运行附加到的脚本标签。例如,如果您执行以下操作:domReady(function(){alert();});
,则会将以下内容附加到body
元素:
<script>(function (){alert();})();</script>
请注意,这仅适用于用户定义的功能。以下内容不起作用:domReady(alert);
这个解决方案怎么样?
// 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();
};
与jQuery相比,使用JavaScript等效项总是好事。原因之一是要减少依赖的库,而且它们比jQuery等效库快得多。
http://youmightnotneedjquery.com/是jQuery等价物的绝佳参考。
就您的问题而言,我从上面的链接中获取了以下代码:)请注意,它仅适用于Internet Explorer 9和更高版本。
function ready(fn) {
if (document.readyState != 'loading') {
fn();
}
else {
document.addEventListener('DOMContentLoaded', fn);
}
}
我从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帮助器的可行替代品。
是2020年,<script>
标签具有defer
属性。
例如:
<script src="demo_defer.js" defer></script>
它指定在页面完成解析后执行脚本。
这里介绍的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团队用来构建其实现的代码。
这就是我使用的方法,它快速且涵盖了我认为的所有基础;适用于IE <9以外的所有功能。
(() => { function fn() {
// "On document ready" commands:
console.log(document.readyState);
};
if (document.readyState != 'loading') {fn()}
else {document.addEventListener('DOMContentLoaded', fn)}
})();
这似乎可以解决所有情况:
DOMContentLoaded事件在IE9和其他所有版本中都可用,因此我个人认为可以使用它。如果您没有将代码从ES2015转换为ES5,则将arrow函数声明重写为常规的匿名函数。
如果要等到所有资产都加载完毕,则显示的所有图像等将改为使用window.onload。
如果您不必支持非常老的浏览器,即使您的外部脚本加载了async属性,也可以使用以下方法:
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");
});
尝试这个:
function ready(callback){
if(typeof callback === "function"){
document.addEventListener("DOMContentLoaded", callback);
window.addEventListener("load", callback);
}else{
throw new Error("Sorry, I can not run this!");
}
}
ready(function(){
console.log("It worked!");
});
function onDocReady(fn){
$d.readyState!=="loading" ? fn():document.addEventListener('DOMContentLoaded',fn);
}
function onWinLoad(fn){
$d.readyState==="complete") ? fn(): window.addEventListener('load',fn);
}
当HTML dom准备完全访问/解析/操作时,onDocReady提供回调。
当所有内容加载完毕(图像等)时,onWinLoad提供回调
(function(f){
if(document.readyState != "loading") f();
else document.addEventListener("DOMContentLoaded", f);
})(function(){
console.log("The Document is ready");
});
大多数香草JS Ready函数不会考虑在 文档已加载后DOMContentLoaded
设置处理程序的情况-这意味着该函数将永远不会运行。如果您在外部脚本()中查找,可能会发生这种情况。DOMContentLoaded
async
<script async src="file.js"></script>
下面的代码DOMContentLoaded
仅在文档readyState
不是interactive
或时检查complete
。
var DOMReady = function(callback) {
document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback());
};
DOMReady(function() {
//DOM ready!
});
如果您也要支持IE:
var DOMReady = function(callback) {
if (document.readyState === "interactive" || document.readyState === "complete") {
callback();
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', callback());
} else if (document.attachEvent) {
document.attachEvent('onreadystatechange', function() {
if (document.readyState != 'loading') {
callback();
}
});
}
};
DOMReady(function() {
// DOM ready!
});
我只是使用:
setTimeout(function(){
//reference/manipulate DOM here
});
而且与document.addEventListener("DOMContentLoaded" //etc
最高答案不同,它的工作最早可以追溯到IE9- http ://caniuse.com/#search=DOMContentLoaded仅表示IE11。
有趣的是,我setTimeout
在2009年偶然发现了此解决方案:是否正在检查DOM是否已准备就绪?,这可能用更好的措辞来表达,因为我的意思是“使用各种框架的更复杂的方法来检查DOM的就绪性是否为时过早”。
我对这种技术为何有效的最好解释是,当到达具有这样的setTimeout的脚本时,DOM处于解析的中间,因此setTimeout中代码的执行将推迟到该操作完成之前。