事件浅谈之事件冒泡

什么是事件?

简单来说,事件就是文档或浏览器窗口发生的一些特定的交互瞬间。它最早时是用作分担服务器运算负载的一种手段。后来DOM2级规范开始尝试以一种符合逻辑的方式来标准化DOM事件。但是它并没有规范所有的事件类型。后来,DOM3级又增强了DOM事件的API。我们所熟悉的BOM也支持一些事件, 但BOM事件长期并没有规范,而且它支持的这些事件与DOM事件的关系也不太明确。使用事件有时复杂,有时相对简单,难度会因为需求的不同而不同。

事件流

事件流描述是从页面中接收事件的顺序。举例:
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style type="text/css">
		div{
			padding:40px;
		}
		#div1{
			background:red;
		}
		#div2{
			background:blue;
		}
		#div3{
			background:green;
		}
	</style>
	<script type="text/javascript">
		window.onload = function(){
			var oDiv1= document.getElementById('div1');
			var oDiv2 = document.getElementById('div2');
			var oDiv3 = document.getElementById('div3');
			function fn (){
				alert(this.id)
			}
			oDiv1.onclick = fn;
			oDiv2.onclick = fn;
			oDiv3.onclick = fn;
		}
	</script>
</head>
<body>
	<div id="div1">
		<div id="div2">
			<div id="div3"></div>
		</div>
	</div>
</body>
</html>
效果展示:

当点击绿色DIV时,会依次弹出三次三个Id,分别是Div1、Div2、Div3。并不是因为他们的样式表现,而是因为html结构。如下代码,结果同上:
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style type="text/css">
		div{
			padding:40px;
		}
		#div1{
			background:red;
		}
		#div2{
			background:blue;
		}
		#div3{
			background:green;
			position: absolute;
			top:300px;
		}
	</style>
	<script type="text/javascript">
		window.onload = function(){
			var oDiv1= document.getElementById('div1');
			var oDiv2 = document.getElementById('div2');
			var oDiv3 = document.getElementById('div3');
			function fn (){
				alert(this.id)
			}
			oDiv1.onclick = fn;
			oDiv2.onclick = fn;
			oDiv3.onclick = fn;
		}
	</script>
</head>
<body>
	<div id="div1">
		<div id="div2">
			<div id="div3"></div>
		</div>
	</div>
</body>
</html>
效果展示:
事件流包含两个内容:
  1. 事件冒泡流
  2. 事件捕获流

事件冒泡

先说一下,如果你点击了某个按钮,你也一定单击了它的父级,父级的父级的父级......
拿上述的两个例子,事件冒泡就是从事件开始的元素接收然后逐级向上传播到window对象,
<div>--><body>--><html>-->document
所有现代浏览器都支持事件冒泡,但在具体实现上还是有一些差别。IE5.5及更早版本中的事件冒泡会跳过<html>元素,其他浏览器(IE9、Firefox、Chrome、Safari)则将事件一直冒泡到window对象。
首先,点击oDiv1对象,然后触发点击事件,执行fn函数,然后传播事件到它的父级oDiv2,如果oDiv2接收到一个点击事件,那么他就执行fn函数。(事件函数绑定:把一个函数与事件进行绑定,事件发生时执行函数)再传播事件到oDiv2的父级oDiv3,如果oDiv3接收到一个点击事件,那么他就执行fn函数。
如果我们删除
oDiv2.onclick = fn;
这行代码,结果依然会弹出id为Div1的id,那么为什么会出现这种情况呢?因为这种操作并没影响oDiv2事件的发生和接收。会影响的只是事件发生以后要做的事情,即fn函数的执行,没有绑定就不会执行,所以没有显示,但是它还是会把事件传播给oDiv1,而oDiv1绑定了fn函数,所以,它弹出了oDiv1的id。

实例:下拉菜单

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style type="text/css">
		div{
			width:100px;
			height:200px;
			border:1px solid #000;
			background:pink;
			display: none
		}
	</style>
	<script type="text/javascript">
		window.onload = function(){
			var oBtn = document.getElementsByTagName('input')[0];
			var oDiv = document.getElementById('div')
			oBtn.onclick = function(){
				oDiv.style.display = "block";
			}
			document.onclick = function(){
				oDiv.style.display = 'none';
				
			}
		}
	</script>
</head>
<body>
	<input type="button" value="下拉按钮"/>
	<div id="div"></div>
</body>
</html>
执行的时候按钮怎么都不会打开下拉列表,因为当点击按钮的时候,触发点击事件,执行绑定函数:
function(){
	oDiv.style.display = "block";
}
正常情况下,下拉列表会出现,但是因为下段代码出现导致出现没打开的现象
document.onclick = function(){
	oDiv.style.display = 'none';
				
}
实际上,下拉列表打开了,因为时间太快所以并没有看见,在看不见的时间里,由于事件冒泡,oDiv把事件传播到了它的父级的父级的父级即document对象,document对象恰好有绑定的函数,它的功能是把oDiv的display属性值变为none,所以,在看不见的时间里,发生了确实发生的事情。为了看的更明显,可以加一个定时器。代码如下:
document.onclick = function(){
				setTimeout(function(){
					oDiv.style.display = 'none';
				},1000)//1s之后执行
				
			}

如此看来,事件冒泡好像变得有点麻烦,缺点变得显而易见,那么为什么还要把它设置为默认存在的呢?因为他的优点不可忽略。

事件冒泡的优点:

假如事件冒泡不存在,我们还是实现如上效果:点击按钮下拉出现,点击除按钮以为的任何元素下拉列表消失。
那么,我们要做的是给页面里除按钮以外的所有元素都加上点击事件,这样庞大的工程......像我是绝对做不下去的。但是如果有事件冒泡这种事件流,就很方便,我们 只需要给共同的父级加事件处理例如:body标签,利用事件冒泡,用任何一个子元素都会把事件传播给文档,让文档去做这件事,会轻松很多。解决上面出现的问题,只需要阻止oBtn的事件冒泡就可以了。
event.cancleBubble = true;//默认情况为false

实例:分享到



 
子级冒泡到父级

发布了37 篇原创文章 · 获赞 3 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章