今天来总结下在项目中事件使用的以下问题
*DOMContentLoaded在不同浏览器的实现
什么是DOMContentLoaded? 它是firefox为了处理在页面DOM结构建立后(无需下载js,css,img等图片资源)绑定事件的一个方法,对于IE是没有这个方法的,但是在IE中可以模拟出这个方法来,来达到同样的目的。我们经常使用jquery的 $(document).ready(function(){});或者百度的tangram框架的时候, baidu.dom.ready(function(){})其实是对这个方法在不同浏览器中做了一个封装。
在IE中的实现方式,我们可以参考这个文档http://javascript.nwbox.com/IEContentLoaded/ ,他的原理是:在IE下,DOM的某些方法只有在DOM解析完成后才可以调用,doScroll就是这样一个方法,当然反过来当能调用doScroll的时候即是DOM解析完成之时。下面我们来看看jquery和tangram的实现方式,来加深理解
1)jquery
bindReady: function() {
if ( readyList ) {
return;
}
readyList = jQuery.Callbacks( "once memory" );
// 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( jQuery.ready, 1 );
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// 给加载在document上去。
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// 确保事件真正的执行
window.addEventListener( "load", jQuery.ready, false );
// 如果是IE的事件模式
} else if ( document.attachEvent ) {
// ensure firing before onload,
// 如果是是iframe的形式的话
document.attachEvent( "onreadystatechange", DOMContentLoaded );
// 确保这个函数被真正的使用了
window.attachEvent( "onload", jQuery.ready );
// 如果是IE序列的浏览器,并且不是在iframe使用
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
//如果支持doScroll 并且不是在iframe的时候
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
}
// 在IE序列浏览器下,检测 DOM ready
function doScrollCheck() {
if ( jQuery.isReady ) {
return;
}
try {
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
//执行该要执行的函数
jQuery.ready();
}
在代码中我都解释了。
2)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();
}
};
}
function ready() {
if (!ready.isReady) {
ready.isReady = true;
for (var i = 0, j = readyList.length; i < j; i++) {
readyList[i]();
}
}
}
function doScrollCheck(){
try {
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
ready();
}
function bindReady() {
if (readyBound) {
return;
}
readyBound = true;
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[readyList.length] = callback);
};
}();
ready.isReady = false;
})();
可以看出tangram的实现方式和jquery一样的。
*阻止事件默认行为
判断是否支持 preventDefault 函数,如果不支持的话,就将事件的属性returnValue 设置为false,常见的写法为
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
*阻止事件传播
判断是否支持stopPropagation,如果不支持的话,就将事件的属性cancelBubble设置为true,常见的写法为
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
*获取对象
target = event.srcElement ||event.target
*获取鼠标事件的X,Y坐标
x = event.pageX !== 0 ?event.pageX:event.clientX +document.body.scrollLeft||document.documentElement.scrollLeft;
y = event.pageY !== 0 ?event.pageY:event.clientY +document.body.scrollTop||document.documentElement.scrollTop;
*获取键盘的键值
value = event.which || event.keyCode;
*事件的其他属性
事件的相关对象,处理从一个节点到其子节点中处理很方便的,标准浏览器是支持 relatedTarget ,在IE下是不一样的。
var reltarget = e.relatedTarget ? e.relatedTarget : e.type == 'mouseout' ? e.toElement:e.fromElement;
*事件注意点
绑定事件的时候一定要搞清楚事件的对象,事件句柄,事件的触发条件
欢迎大家拍砖。。