终于学生生涯最后一个寒假也就这么的过完了,昨天回到川大,休息了一天,今天正式开始做毕设了。
晚上看完 年代秀,不想码代码,所以就把寒假在家学习的一些分享出来。
之前在学校,由于项目一般工期都狠紧张,所以频繁使用Jquery,后来Jquery用多了,反而原生的JS感觉很陌生了。寒假的时候,顺便看了看kissy,tangram,然后自己慢慢开始写一个库,通过编写这种库来学习JS。
在原生的JS中,使用window.onload可以实现当文档载入之后执行一段代码,但是window.onload只能执行一次,而且它必须要等到包括图片等元素全部载入之后才能执行,很不友好,所以各个JS的库都有ready这个函数,如Jquery中,$(document).ready,这个函数函数可以执行多次,并且当DOM结构绘制完毕之后就会执行,不必等到所有元素全部载入,所以它的执行要比window.onload要早。
由于我上学期面试百度前端的时候被面试官无情的刷掉了,但是他推荐了tangram给我,所以这个寒假看的最多的就是tangram,希望借此提高自己JS水平。
PS:说起这个,还需要对tohilary说声sorry了,之前你在oschina上和我交流说希望把toper放到github上面,我答应你寒假去修改一下toper,结果我寒假去搞JS去了,由于我是单核的,并发能力不强,所以基本上没有做这个。
我看了一下tangram关于ready的实现(baidu.dom.ready),基本上和Jquery的实现相同。tangram的实现代码如下:
(function() {
var ready = baidu.dom.ready = function() {
var readyBound = false,
readyList = [],
DOMContentLoaded;
if (document.addEventListener) {
DOMContentLoaded = function() {
document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false);
ready();
};
} else if (document.attachEvent) {
DOMContentLoaded = function() {
if (document.readyState === 'complete') {
document.detachEvent('onreadystatechange', DOMContentLoaded);
ready();
}
};
}
/**
* @private
*/
function ready() {
if (!ready.isReady) {
ready.isReady = true;
for (var i = 0, j = readyList.length; i < j; i++) {
readyList[i]();
}
}
}
/**
* @private
*/
function doScrollCheck(){
try {
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
ready();
}
/**
* @private
*/
function bindReady() {
if (readyBound) {
return;
}
readyBound = true;
if (document.readyState === 'complete') {
ready.isReady = true;
} else {
if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', DOMContentLoaded, false);
window.addEventListener('load', ready, false);
} else if (document.attachEvent) {
document.attachEvent('onreadystatechange', DOMContentLoaded);
window.attachEvent('onload', ready);
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch (e) {}
if (document.documentElement.doScroll && toplevel) {
doScrollCheck();
}
}
}
}
bindReady();
return function(callback) {
ready.isReady ? callback() : readyList.push(callback);
};
}();
ready.isReady = false;
})();
代码不是很多,实现原理也并不复杂,(function(){})()这种方式可以自动执行function里面的代码,并且保证这些代码不被其他代码污染,我很喜欢这种写法。
ready的基本原理就是当这段代码执行的时候,它会添加一个事件监听器来监听是否文档树已经被载入完成,如果没有完成,则把ready的回调函数加入到等待的队列,如果载入完成,首先移除事件监听器,并且执行队列里面的所有回调函数。
事件监听则按照是否是IE而不同,IE使用atachEvent添加事件监听器,detchEvent移除事件监听器,并且这里的事件都是以on开头,如onXXX,而W3C的浏览器使用addEventListener和removeEventListener来添加或移除事件监听器。
PS:IE只支持冒泡,而W3C的支持捕获和冒泡。
readyBound用来判定是否已经 绑定了事件,isReady用来判定是否DOM已经载入完成,readyList是一个队列,用来存储在DOM载入完成前调用ready的回调函数。
在firefox,opera和webkit内核的浏览器(如chrome)中,它支持DOMContentLoaded这个事件,所以可以直接使用DOMContentLoaded来判定,非常简单;在IE中,可以利用IE的一个trick,可以点击这里查看详细内容,基本原理就是利用IE在文档载入完成前执行document.documentElement.doScroll("left")会出错,通过try catch来不断测试,一旦它不出错了,即文档载入完成了,如:
try {
document.documentElement.doScroll('left');
} catch (e) {
setTimeout(arguments.callee, 50);
return;
}
而如果以上措施还不行,就使用window.onload,这样可以确保载入完成后可以执行回调。
window.frameElement这个可以来判定是否是frame这种情况,如果是那么会返回对象,否则会返回undefined。
好了,就说这么多吧!!