IE中的事件流叫事件冒泡,事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档)。对于html来说,就是当一个元素产生了一个事件,它会把这个事件传递给它的父元素,父元素接收到了之后,还要继续传递给它的上一级元素,就这样一直传播到document对象(亲测现在的浏览器到window对象,只有IE8及下不这样);
再多说一句,现在的浏览器默认是采用的是事件冒泡(重点,圈起来);在DOM0级方法绑定事件只能是事件冒泡,不能设置;在DOM2级你可以设置是用事件冒泡还是事件捕获。 有图有真相,发图不留种,菊花万人捅。
![js事件流 - 眷恋天空的驴 - javscript js事件流 - 眷恋天空的驴 - javscript](http://img2.ph.126.net/2nuEG_2yHnxjJth5zdfdGQ==/6631902295024385693.png)
(ps:很形象的事件冒泡原理事件图)
2 事件捕获
事件捕获 是网景(Netscape)提出来的,事件捕获是不太具体的元素应该更早接受到事件,而最具体的节点应该最后接收到事件。他们的用意是在事件到达目标之前就捕获它;也就是跟冒泡的过程正好相反,以html的click事件为例,document对象(DOM级规范要求从document开始传播,但是现在的浏览器是从window对象开始的)最先接收到click事件的然后事件沿着DOM树依次向下传播,一直传播到事件的实际目标;我测试了一下(我用的都是最新的浏览器),chrome,opera,firefox,IE11到IE9都支持事件捕获。
ps: 事件捕获很事件冒泡完全是一个逆过程。
3 DOM事件流
DOM2 级中规定了事件流要包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。这是W3C采用了他们两家的事件监听机制。(说点题外话,w3c中的很多标准就是这样,浏览器厂商有很多自己的私有解决问题方式,好用的就被W3c采纳了)DOM2级还规定,实际发生事件的元素在捕获阶段不能接收到事件。我们就以上面的事件冒泡时的代码说明这个过程:按照标准是这样的,当一个元素产生了事件,事件是从document到html再到body再到DIV爷爷再到DIV爸爸,这时候捕获阶段就应该停止了,再进入下一个阶段“处于目标阶段”,然后是从DIV爸爸到DIV爷爷再到body再到html再到document,这就是事件冒泡阶段;实际上我们把处于目标阶段即第二阶段看作是冒泡阶段的一部分,即冒泡的开始;
![js事件流 - 眷恋天空的驴 - javscript js事件流 - 眷恋天空的驴 - javscript](http://img2.ph.126.net/8VWYi5CWGvpzaFkBqLKJtg==/6631872608210436074.png)
友善提醒:由于老版本浏览器不支持,很少有人使用事件捕获。建议使用事件冒泡
4.事件冒泡最常见的应用:--事件代理(事件委托)
传统的事件处理中,需要为每个元素添加事件处理器。js事件代理则是一种简单有效的技巧,通过它可以把事件处理器添加到一个父级元素上,从而避免把事件处理器添加到多个子级元素上。
事件代理的原理用到的就是事件冒泡和目标元素,把事件处理器添加到父元素,等待子元素事件冒泡,并且父元素能够通过target(IE为srcElement)判断是哪个子元素,从而做相应处理。关于target更多内容请参考javaS
<body>< ul id ="color-list" >< li >red </ li >< li >orange </ li >< li >yellow </ li >< li >green </ li >< li >blue </ li >< li >indigo </ li >< li >purple </ li ></ ul ><script>
(function(){
var colorList=document.getElementById("color-list");
colorList.addEventListener('click',showColor,false);
function showColor(e)
{
e=e||window.event;
var targetElement=e.target || e.srcElement; // 要是这个东西都看不懂,我只能呵呵让你跳出这篇文章。好吧。来
if(targetElement.nodeName.toLowerCase()==="li"){
alert(targetElement.innerHTML);
}
}
})();
</script>
</body>
最后在脑补一下DOM0级事件处理跟DOM1级处理,免得有人看不懂这个是什么JB玩意。
DOM0级事件处理程序
这种方法简单而且跨浏览器,但是只能为一个元素添加一个事件处理函数。因为这种方法为元素添加多个事件处理函数,则后面的会覆盖前面的。
<input id="myBtn" type="button" value="click me!"/>
<script>
var myBtn=document.getElementById("myBtn");
myBtn.on
click=function(){ alert("clicked!");
}
</script>
// 删除事件或者清理事件的:
myBtn.onclick=null;
DOM2级事件处理程序
DOM2级事件处理程序可以为一个元素添加多个事件处理程序。其定义了两个方法用于添加和删除事件处理程序:addEventListener()和removeEventListener()。【ps: 完美封装请查看 下面有个事件处理 】
这两个方法都需要3个参数:事件名,事件处理函数,布尔值。
这个布尔值为true,在捕获阶段处理事件,为false,在冒泡阶段处理事件,默认为false。
添加事件处理程序:现在为按钮添加两个事件处理函数,一个弹出“hello”,一个弹出“world”。
<input id="myBtn" type="button" value="click me!"/> <script> var myBtn=document.getElementById("myBtn"); myBtn.addEventListener("click",function(){ alert("hello"); },false); myBtn.addEventListener("click",function(){ alert("world"); },false); </script>
删除事件处理程序:通过addEventListener添加的事件处理程序必须通过removeEventListener删除,且参数一致。
note:通过addEventListener添加的匿名函数将无法删除。下面这段代码将不起作用!【ps: 完美封装请查看 下面有个事件处理 】
1、实际应用场景
2、IE8事件绑定
IE8及以下版本浏览器实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。
这两个方法都需要两个参数:事件处理程序名称和事件处理程序函数。
note:
IE11只支持addEventListener!
IE9,IE10对attachEvent和addEventListener都支持!
TE8及以下版本只支持attachEvent!
可以拿下面代码在IE各个版本浏览器中进行测试。
note:IE事件处理程序中还有一个地方需要注意:作用域。可以查看完美封装中是做了这一步的处理的。
使用attachEvent()方法,事件处理程序会在全局作用域中运行,因此this等于window。
而dom2或dom0级的方法作用域都是在元素内部,this值为目标元素。
下面例子会弹出true。
<input id="myBtn" type="button" value="click me!"/>
<script>
var myBtn=document.getElementById("myBtn");
myBtn.attachEvent("onclick",function(){
alert(this===window);
});
</script>