$(document).ready(function (){ alert('use in page script tag') });
$(document).ready(function (){ alert('use in import js file') });
现在让我们来研究一下这个函数的实现.
原理:
在jquery脚本加载的时候,会设置一个isReady的标记,监听DOMContentLoaded事件(这个不是什么浏览器都有的,不同浏览器,jquery运作方式不一样).当然遇到调用ready函数的时候,如果isReady未被设置,那就是说页面未加载完,就会把要执行的函数用一个数组缓存起来,当页面加载完后,再把缓存的函数一一执行.
Jquery中的详细代码分析:
代码如下:
ready: function(fn) {
// 绑定监听器
bindReady();
// 如果 DOM 加载完成
if ( jQuery.isReady )
// 马上运行此函数
fn.call( document, jQuery );
// 否则保存起来
else
// 把函数加入缓存数组中
jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
return this;
}
代码如下:
var readyBound = false;
function bindReady(){
if ( readyBound ) return;
readyBound = true;
// Mozilla,opera,webkitnightlies支持DOMContentLoaded事件
if ( document.addEventListener && !jQuery.browser.opera)
// 直接使用事件回调即可
document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
// 如果是ie并且不是嵌在frame中
// 就需要不断地检查文档是否加载完
if ( jQuery.browser.msie && window == top ) (function(){
if (jQuery.isReady) return;
try {
// 这个地方标记一下,在后面解析(1)
document.documentElement.doScroll("left");
} catch( error ) {
这个地方标记一下,在后面解析(2)
setTimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
jQuery.ready();
})();
if ( jQuery.browser.opera )
document.addEventListener( "DOMContentLoaded", function () {
if (jQuery.isReady) return;
for (var i = 0; i < document.styleSheets.length; i++) // 标记(3)
if (document.styleSheets[i].disabled) {
setTimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
jQuery.ready();
}, false);
if ( jQuery.browser.safari ) {
var numStyles;
(function(){
if (jQuery.isReady) return;
if ( document.readyState != "loaded" && document.readyState != "complete" ) { // 标记(4)
setTimeout( arguments.callee, 0 );
return;
}
if ( numStyles === undefined )
numStyles = jQuery("style, link[rel=stylesheet]").length;
if ( document.styleSheets.length != numStyles ) { // 标记(5)
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 ); // 标记(6)
}
}
(2):setTimeout( arguments.callee, 0 )这句是表示延迟0秒调用,实际上它不会马上就调用,而是会尽可能快地调用,它告诉浏览器为当前任何挂起的事件运行完事件句柄并且完成了文档当前状态的更新后才调用. Arguments.callee即是外层的匿名函数,参数的调用者
(3):这个地方你也许觉得奇怪,为什么不在mozilla那里一起处理呢? 原因就是opera的DOMContentLoaded事件发生后,其css样式是还没完全可用的,所以要特殊处理,就是判断每个css的tag都是不是enable了.
(4),(5):safari中document.readyState的状态为loaded或complete时,css文件引入还未能确定是不是解析完了的,所以要通过判断其css文件数目
(6):最后,如果上面的hack都不支持的话…就用最保险的load事件,保证能执行到初始化代码.
//浏览器检测
(function () {
window.sys = {};
var ua = navigator.userAgent.toLowerCase();
var s;
(s = ua.match(/msie ([\d.]+)/)) ? sys.ie = s[1] :
(s = ua.match(/firefox\/([\d.]+)/)) ? sys.firefox = s[1] :
(s = ua.match(/chrome\/([\d.]+)/)) ? sys.chrome = s[1] :
(s = ua.match(/opera\/.*version\/([\d.]+)/)) ? sys.opera = s[1] :
(s = ua.match(/version\/([\d.]+).*safari/)) ? sys.safari = s[1] : 0;
if (/webkit/.test(ua)) sys.webkit = ua.match(/webkit\/([\d.]+)/)[1];
})();
//DOM加载
function addDomLoaded(fn) {
var isReady = false;
var timer = null;
function doReady() {
if (timer) clearInterval(timer);
if (isReady) return;
isReady = true;
fn();
}
if ((sys.opera && sys.opera < 9) || (sys.firefox && sys.firefox < 3) || (sys.webkit && sys.webkit < 525)) {
//无论采用哪种,基本上用不着了
/*timer = setInterval(function () {
if (/loaded|complete/.test(document.readyState)) { //loaded是部分加载,有可能只是DOM加载完毕,complete是完全加载,类似于onload
doReady();
}
}, 1);*/
timer = setInterval(function () {
if (document && document.getElementById && document.getElementsByTagName && document.body) {
doReady();
}
}, 1);
} else if (document.addEventListener) {//W3C
addEvent(document, 'DOMContentLoaded', function () {
fn();
removeEvent(document, 'DOMContentLoaded', arguments.callee);
});
} else if (sys.ie && sys.ie < 9){
var timer = null;
timer = setInterval(function () {
try {
document.documentElement.doScroll('left');
doReady();
} catch (e) {};
}, 1);
}
}