您的位置:首页 > Web前端 > JavaScript

javascript事件处理方式之捕获冒泡

2013-10-28 15:11 615 查看
javascript在事件处理机制上经历了三个阶段 html事件处理、dom0级事件处理、dom2级事件处理。

html事件处理:

形如

<div onclick='alert(this.id)'id="myDiv"></div>

该单击操作是通过onclick特性并将一些js代码作为值来定义。正因为这个值是js,因此不能使用一些未经转义的html语法字符,例如""等,要想使用双引号,上述例子需要修改为:

<div onclick="alert("this.id")"></div>

在html中定义事件处理通常都会调用页面其他地方定义的函数脚本,

<div onclick="clickme()"></div>

在html中定义事件处理有两个缺点:

1.时差问题,用户可能会在html元素一出现在页面上就触发相应事件,但有可能在解析函数之前html加载之后用户单击该元素就会引发错误。

2.html与js代码耦合性较高,想修改一个事件必须修改两处。

DOM0级事件处理:

实现该事件处理首先要得到对html元素操作对象的引用,然后为其指定一个事件处理程序如onclick。

var myBtn=document.getElementById("myDiv");

myBtn.onclick=function(){alert(this.id)}//其中的this指向元素作用域,即表示当前元素。

dom0级事件处理有一个大的缺陷:

如果我们定义两个同样的事件时候,后一个就会把前一个给覆盖掉,例如onclick事件,后一个该元素的onclick就会覆盖前一个的onclick事件。

不过虽然有这么个缺点,开发人员一般都会注意到的,从而很多人还是倾向于应用该处理方式,原因就是写起来简单而且没有浏览器兼容问题。

DOM2级处理事件:

DOM2级事件处理主要通过一个方法addEventListener()来实现,所有dom节点都包含该方法,接受三个参数,要处理事件名,事件处理函数和一个布尔值(该布尔值就是下面将要说到的冒泡和捕获);

var myBtn=document.getElementById("myDiv");

myBtn.addEventListener("click",myFunction,false);

利用该方法可以添加多个事件处理程序,并且可以通过removeEventListener()来移除事件,

需要注意的是第二个参数如果应用匿名函数的话就不能成功将其移除了,所以尽量都写成这种函数名形式便于移除,

同时在ie低版本浏览器中并不是通过该方法实现dom2级事件处理的,而是通过attachEvent和detachEvent()配套完成,

不同的是后者只接受两个参数,第三个布尔值不会接受(因为ie只支持冒泡);

接下来我们讨论一下事件流捕获和冒泡事件处理机制,也就是上面addEventListener的第三个参数代表的意思:



假设我们画一个同心圆,我们点击圆心时候其实指向的不止是最里面那个圆,而是这组同心圆的所有圆,如果我们在这组同心圆都定义了相同的事件,那么是先执行外面的事件还是内部的事件呢?

于是就产生了捕获与冒泡两种不同的处理机制;

捕获:

捕获的思想是不太具体的节点最先接受到事件,而最具体的节点最后接收到事件,达到在事件到达预定目标之前捕获该事件的目的。

冒泡:

冒泡正好相反,即事件最先由具体目标接受,然后逐级传播到最不具体的上级节点文档,可能这因为微软是做操作系统原因,借鉴于其桌面处理方式只支持冒泡。

w3c中和两种不同机制,规定DOM2级事件流包括三个阶段:事件捕获阶段、处于目标阶段、和事件冒泡阶段,

并且规定在捕获阶段不会触发对象上的事件,都是在冒泡阶段进行触发的。而浏览器都会在捕获阶段触发对象事件,于是就有两个机会在目标对象上操作事件。

上面说到addEventListener()方法接受的第三个参数是个布尔值,如果是true时候则在捕获阶段调用事件处理程序,如果是false则是在冒泡阶段处理事件。

举例如下:

<html>

<body>

<div id="div1" style='width: 400px; height: 400px;border: 1px solid #CCCCCC'>

<div id="div2" style='width: 200px; height: 200px;border: 1px solid #CCCCCC'>

</div></div>

</body>

<script>

function $(a){

return document.getElementById(a)

}

function ale(e){alert(this.id)}

</script>

</html>

$('div1').addEventListener('click',ale,false);

$('div2').addEventListener('click',ale,false);

在同时定义情况下点击div2,会先触发div2的事件,然后冒泡到div1再执行div1的事件,

$('div1').addEventListener('click',ale,true);

$('div2').addEventListener('click',ale,false);

如果在div1定义为捕获事件,则事件传播同样会遵从w3c规则,先捕获,div1是捕获阶段触发所以先执行div1事件,

然后再执行div2事件,再向上冒泡检测是否有冒泡事件处理程序,没检测到则返回结束。

$('div1').addEventListener('click',ale,fasle);

$('div2').addEventListener('click',ale,true);

如果在div1定义了冒泡处理程序,div2定义了捕获阶段处理程序,点击div2时候div1没捕获到事件,而div2捕获到了,

于是先触发div2事件,然后冒泡检测是否有冒泡事件定义,div1定义的是冒泡事件,随后就会执行div1事件

$('div1').addEventListener('click',ale,true);

$('div2').addEventListener('click',ale,true);

同时都设置为捕获阶段处理事件,div1首先捕获到事件于是触发div1事件,而后div2捕获到事件,进而执行div2事件,然后向上冒泡没有冒泡处理程序,则返回结束。

通常情况下 我们都不想点击一个元素时候希望它继续向上或者向下传播,w3c为我们提供了取消事件传播的方法:即event.stopPropagation();

而event.perventDefault()则是取消事件默认行为(例如a标签点击跳转).

因为ie的不合作导致浏览器兼容性的出现在这就不做评价了,下面附上ie兼容的一段处理dom2级事件方法:

myEvent={

addEvent: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

}

},

removeEvent:function(ele,type,handler){

if(ele.removeEventListener){

ele.removeEventListener(type,handler,false);

}

else if(ele.datachEvent){

ele.datachEvent('on'+type,handler)

}

else{

ele["on"+type]=null;

}

},

preventDefalut:function(e){

if(e.preventDefault){

e.preventDefault();

}

else{

e.returnValue=false;

}

},

stopPropagation:function(e){

if(e.stopPropagation){

e.stopPropagation();

}

else{

e.cancelBubble=true;

}

}

}

使用方法如下:

myEvent.addEvent(ele,"click",handler);

myEvent.removeEvent(ele,"click",handler);

这个很基本,只是让大家从code层次理解一下事件兼容性的处理
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: