我有一个使用了$(document).ready
的脚本,但它没有使用jQuery的其他任何功能。 我想通过去除jQuery依赖来减轻它的负担。
我如何在不使用jQuery的情况下实现自己的$(document).ready
功能? 我知道使用window.onload
将不同,因为window.onload
会在所有图像、框架等都加载完成后触发。
我有一个使用了$(document).ready
的脚本,但它没有使用jQuery的其他任何功能。 我想通过去除jQuery依赖来减轻它的负担。
我如何在不使用jQuery的情况下实现自己的$(document).ready
功能? 我知道使用window.onload
将不同,因为window.onload
会在所有图像、框架等都加载完成后触发。
有一个基于标准的替代方法,DOMContentLoaded
,它被超过99%的浏览器支持,但不包括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 );
}
document.addEventListener("DOMContentLoaded", function(event)
吗?并且期望它们都会被调用吗? - mercuryfunction ready(fn) {
if (document.readyState !== 'loading') {
fn();
return;
}
document.addEventListener('DOMContentLoaded', fn);
}
来自:https://youmightnotneedjquery.com/
作为一个一行代码的小改进,由Tanuki提供:
const ready = fn => document.readyState !== 'loading' ? fn() : document.addEventListener('DOMContentLoaded', fn);
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
});
jQuery.ready()
的"ready"函数。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>
function r(f){/in/.test(document.readyState)?setTimeout(r,9,f):f()}
r(function(){/*code to run*/});
document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
function ready(fn){(document.readyState!=='loading')?fn():document.addEventListener('DOMContentLoaded',fn)}
当所有资源加载完成时的代码:function load(fn){(document.readyState==='complete')?fn():document.addEventListener('load',fn)}
- undefined三种选择:
script
是body中的最后一个标签,则在script
标签执行前DOM将准备就绪。onreadystatechange
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代码 */</script>
置于紧接着</body>
标签之前。
诚然,这种方法可能并不适合每个人的需求,因为它需要更改HTML文件,而不仅仅是在JavaScript文件中使用document.ready
,但还是值得尝试的...
穷人的解决方案:
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!");
};
})()
我使用这个:
document.addEventListener("DOMContentLoaded", function(event) {
//Do work
});
注意:这可能只适用于更新的浏览器,尤其是这些浏览器:http://caniuse.com/#feat=domcontentloaded
现在是2023年,<script>
标签已经加入了defer
属性。
例如:
<script src="demo_defer.js" defer></script>
它指定脚本在页面完成解析后执行。
在2022年,您只需在脚本上添加defer属性,并在head中加载即可!
参考:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer
<!doctype html>
<html>
<head>
<script src="/script.js" defer></script>
</head>
<body>
<p>In 2022, all you need to do is put the defer attribute on your script, and load it in the head!</p>
</body>
</html>
这个问题很久以前就被提出了。对于刚看到这个问题的人,现在有一个名为"you might not need jquery"的网站,它按照IE支持的级别分解了jQuery的所有功能,并提供了一些替代的、更小的库。
根据you might not need 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);
。 - Luke实际上,如果你只关心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();
}
}
},
$(document).ready
,那么你可以通过在页面底部而不是顶部运行代码来轻松解决这个问题。 HTML5Boilerplate正是采用了这种方法。 - Blazemonger