本文深入解析JavaScript中的事件流机制,包括IE的事件冒泡与Netscape的事件捕获。详细对比DOM0级、DOM2级(addEventListener)及IE特有的attachEvent三种事件处理程序的实现方式、触发顺序及优缺点,并提供跨浏览器兼容的事件处理方案。
JavaScript事件流机制
事件流主要分为两种模式:IE浏览器采用的事件冒泡流,其机制是事件从最具体的目标元素开始接收,随后逐级向上传播至较不具体的节点(即从Element向Document传播);而Netscape浏览器则采用相反的事件捕获流。
根据DOM2级事件规范,完整的事件流包含三个连续阶段:首先是事件捕获阶段,接着是处于目标阶段,最后是事件冒泡阶段。
在实际开发中,通常建议将事件处理程序绑定到事件流的冒泡阶段。以下是一个EventUtil工具类的示例代码。
var EventUtil = {
addHandler: function(element, type, handler){
if(element.addEventListener){
element.addEventListener(type, handler, false);
}else if(element.attachEvent){
element.attachEvent('on' + type, handler); // IE8
}else{
element['on' + type] = handler;
}
},
removeHandler: function(){...}
}
接下来我们将对各类事件处理程序进行详细解析。
DOM0级事件处理程序
DOM0级事件处理程序:这是通过JavaScript指定事件处理程序的传统方式,具体做法是将一个函数赋值给元素的事件处理程序属性。每个元素都拥有自己的事件处理程序属性,这些属性名通常全部小写,例如onclick。只需将该属性的值设置为一个函数,即可为元素指定对应的事件处理程序。
var btn = document.getElementById('myBtn');
// 添加事件处理程序
btn.onclick = function () {
alert( this );//为DOM元素btn
};
// 移除事件处理程序
btn.onclick = null;
优点:1.简单2.具有跨浏览器的优势 缺点:在代码运行之前不会指定事件处理程序,因此这些代码在页面中位于按钮后面,就有可能在一段时间怎么点击都没反应,用户体验变差。
DOM2级事件处理程序
DOM2级事件处理程序:该规范定义了两个核心方法,用于执行指定和移除事件处理程序的操作,分别是addEventListener()和removeEventListener()。这两个方法均接收三个参数:第一个是要处理的事件类型名称;第二个是作为事件处理程序的函数;第三个是一个布尔值,当该值为true时,表示在捕获阶段调用事件处理程序,为false时则表示在冒泡阶段调用。
// 添加多个事件处理程序
var btn = document.getElementById('myBtn');
btn.addEventListener('click',function (){
alert( this );// 为DOM元素btn
},false );
btn.addEventListener('click',function () {
alert('Hello World');
},false);
// 移除事件处理程序
btn.removeEventListener('click',function () {
// 匿名函数无法被移除,移除失败
},false);
// 改写
var handler = function () {
alert(this.id);
};
btn.addEventListener('click',handler,false);
// 再次移除事件处理程序
btn.removeEventListener('click',handler,false);// 移除成功
通过DOM2级方法添加的多个事件处理程序,会严格按照它们被添加的顺序依次触发。鉴于大多数情况下建议将事件处理程序添加到冒泡阶段,这种做法能够最大限度地兼容各种版本的浏览器。
DOM2级事件处理程序的优点在于允许为一个元素添加多个事件处理程序。其主要缺点是不兼容IE8及更低版本的浏览器(包含IE8)。
IE事件处理程序
IE事件处理程序:IE浏览器定义了两个类似的方法,分别为attachEvent()和detachEvent()。这两个方法接收两个参数:事件处理程序名称和事件处理程序函数。由于IE8及更早版本的浏览器仅支持事件冒泡机制,因此通过detachEvent()移除的事件处理程序实际上是从冒泡阶段中移除的。
var btn = document.getElementById('myBtn');
btn.attachEvent('onclick', function(){
alert( this );// window
});
btn.attachEvent('onclick', funciton(){
alert("HELLO, WORLD");
});
在IE浏览器中,点击按钮时这两个事件处理程序的触发顺序与前述DOM2级机制恰好相反。它们并非按照添加事件处理程序的顺序触发,而是以相反的顺序执行。
IE事件处理程序的优点同样是一个元素可以添加多个事件处理程序。其显著缺点是仅支持IE浏览器,缺乏跨浏览器兼容性。
跨浏览器事件处理方案
为了实现跨浏览器的事件处理,需要封装统一的处理逻辑。
以下是一个跨浏览器事件处理程序的示例代码,展示了如何兼容不同浏览器的事件绑定与移除操作。
var EventUtil = {
addHandler : function ( ele, type, handler ) {
if ( ele.addEventListener ) {
ele.addEventListener( type, handler, false );
} else if ( ele.attachEvent ) {
ele.attachEvent( 'on' + type, handler );
} else {
ele['on' + type] = handler
}
},
removeHandler: function ( ele, type, handler ) {
if ( ele.removeEventListener ) {
ele.removeEventListener( type, handler, false );
} else if ( ele.detachEvent ) {
ele.detachEvent( 'on' + type, handler );
} else {
ele[ 'on' + type ] = null;
}
}
}