首页 > 代码库 > 深入理解DOM事件机制系列第一篇——事件流
深入理解DOM事件机制系列第一篇——事件流
目录
[1]历史 [2]事件冒泡 [3]事件捕获[4]事件流前面的话
javascript操作CSS称为脚本化CSS,而javascript与HTML的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间,而事件流(又叫事件传播)描述的是从页面中接收事件的顺序。本文将详细介绍该部分的内容
历史
当浏览器发展到第四代时(IE4及Netscape4),浏览器开发团队遇到了一个很有意思的问题:页面的哪一部分会拥有某个特定的事件?想象画在一张纸上的一组同心圆。如果把手指放在圆心上,那么手指指向的不是一个圆,而是纸上的所有圆
两家公司的浏览器开发团队在看待浏览器事件方面还是一致的。如果单击了某个按钮,他们都认为单击事件不仅仅发生在按钮上,甚至也单击了整个页面
但有意思的是,IE和Netscape开发团队居然提出了差不多是完全相反的事件流的概念。IE的事件流是事件冒泡流,而Netscape的事件流是事件捕获流
事件冒泡
IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)
以下列HTML结构为例,说明事件冒泡、事件捕获及事件流
<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><body><div></div></body> </html>
如果单击了页面中的<div>元素,那么这个click事件沿DOM树向上传播,在每一级节点上都会发生,按照如下顺序传播:
(1) <div>(2) <body>(3) <html>(4) document
[注意]所有现代浏览器都支持事件冒泡,但在具体实现在还是有一些差别。IE9、Firefox、Chrome、Safari将事件一直冒泡到window对象
(1) <div>(2) <body>(3) <html>(4) document(5) window
<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><body><div id="box" style="height:100px;width:300px;background-color:pink;"></div><button id="reset">还原</button><script>//IE8-浏览器返回div body html document//其他浏览器返回div body html document windowreset.onclick = function(){history.go();}box.onclick = function(){box.innerHTML += ‘div\n‘;}document.body.onclick = function(){box.innerHTML += ‘body\n‘;}document.documentElement.onclick = function(){box.innerHTML += ‘html\n‘;}document.onclick = function(){box.innerHTML += ‘document\n‘;}window.onclick = function(){box.innerHTML += ‘window\n‘;}</script></body> </html>
<iframe style="width: 100%; height: 140px;" src="http://sandbox.runjs.cn/show/z7c9efsx" frameborder="0" width="320" height="240"></iframe>
事件捕获
事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前就捕获它
以同样的HTML结构为例,说明事件捕获
<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><body><div></div></body> </html>
在事件捕获过程中,document对象首先接收到click事件,然后事件沿DOM树依次向下,一直传播到事件的实际目标,即<div>元素
(1) document(2) <html>(3) <body>(4) <div>
[注意]IE9、Firefox、Chrome、Safari等现代浏览器都支持事件捕获,但是从window对象开始捕获
(1) window(2) document(3) <html>(4) <body>(5) <div>
addEventListener()方法中的第三个参数设置为true时,即为事件捕获阶段
<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><body><div id="box" style="height:100px;width:300px;background-color:pink;"></div><button id="reset">还原</button><script>//IE8-浏览器不支持//其他浏览器返回window document html body divreset.onclick = function(){history.go();}box.addEventListener(‘click‘,function(){box.innerHTML += ‘div\n‘},true)document.body.addEventListener(‘click‘,function(){box.innerHTML += ‘body\n‘;},true);document.documentElement.addEventListener(‘click‘,function(){box.innerHTML += ‘html\n‘;},true);document.addEventListener(‘click‘,function(){box.innerHTML += ‘document\n‘;},true);window.addEventListener(‘click‘,function(){box.innerHTML += ‘window\n‘;},true);</script></body> </html>
<iframe style="width: 100%; height: 140px;" src="http://sandbox.runjs.cn/show/fl3ciasz" frameborder="0" width="320" height="240"></iframe>
事件流
事件流又称为事件传播,DOM2级事件规定的事件流包括三个阶段:事件捕获阶段(capture phase)、处于目标阶段(target phase)和事件冒泡阶段(bubbling phase)
首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件,最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应
<script type="text/javascript">// 0){ return; } if(select[i].getBoundingClientRect().top <= 0 && select[i+1]){ if(select[i+1].getBoundingClientRect().top > 0){ change(oCon.children[i+2]) } }else{ change(oCon.children[select.length+1]) } }}document.body.onmousewheel = wheel;document.body.addEventListener(‘DOMMouseScroll‘,wheel,false);var oCon = document.getElementById("content");var close = oCon.getElementsByTagName(‘span‘)[0];close.onclick = function(){ if(this.innerHTML == ‘显示目录‘){ this.innerHTML = ‘ב; this.style.background = ‘‘; oCon.style.border = ‘2px solid #ccc‘; oCon.style.width = ‘‘; oCon.style.height = ‘‘; oCon.style.overflow = ‘‘; oCon.style.lineHeight = ‘30px‘; }else{ this.innerHTML = ‘显示目录‘; this.style.background = ‘#3399ff‘; oCon.style.border = ‘none‘; oCon.style.width = ‘60px‘; oCon.style.height = ‘30px‘; oCon.style.overflow = ‘hidden‘; oCon.style.lineHeight = ‘‘; }}for(var i = 2; i < oCon.children.length; i++){ oCon.children[i].onmouseover = function(){ this.style.color = ‘#3399ff‘; } oCon.children[i].onmouseout = function(){ this.style.color = ‘inherit‘; if(this.mark){ this.style.color = ‘#3399ff‘; } } oCon.children[i].onclick = function(){ change(this); } }function change(_this){ for(var i = 2; i < oCon.children.length; i++){ oCon.children[i].mark = false; oCon.children[i].style.color = ‘inherit‘; oCon.children[i].style.textDecoration = ‘none‘; oCon.children[i].style.borderColor = ‘transparent‘; } _this.mark = true; _this.style.color = ‘#3399ff‘; _this.style.textDecoration = ‘underline‘; _this.style.borderColor = ‘#2175bc‘; }// ]]></script>深入理解DOM事件机制系列第一篇——事件流