终于学生生涯最后一个寒假也就这么的过完了,昨天回到川大,休息了一天,今天正式开始做毕设了。
晚上看完 年代秀,不想码代码,所以就把寒假在家学习的一些分享出来。
之前在学校,由于项目一般工期都狠紧张,所以频繁使用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。
好了,就说这么多吧!!