文章目录
- JavaScript 事件流
- 概述
- 事件冒泡
- 简介
- onclick() 事件冒泡
- addEventListener() 事件冒泡
- stopPropagation() 阻止事件冒泡
 
- 事件捕获
- 简介
- addEventListener() 事件捕获
- W3C标准事件流
 
- 取消事件默认行为
- 取消使用对象属性绑定的事件的默认行为
- 取消使用addEventListener()绑定的事件的默认行为
 
- 案例
- 利用事件冒泡实现分享功能
 
 
JavaScript 事件流
概述
事件流描述的是从页面中接受事件的顺序。IE和Netscape开发团队提出了两个截然相反的事件流概念,IE的事件流是事件冒泡(event bubbling),Netscape的事件流是事件捕获(event capturing)。
事件冒泡
简介
事件冒泡:当一个元素接收到事件时,会把它接收到的事件逐级向上传播给它的祖先元素,一直传到顶层的window对象。
顶层对象不同浏览器有可能不同,如IE9及以上版本、FireFox、Chrome、Safari等浏览器,事件冒泡的顶层对象为window对象,而IE7/8顶层对象则为document对象。

说明:当用户点击了<div>元素,这时click事件将按照<div> -> <body> -> <html> -> document -> window的顺序进行传播。
可以把事件冒泡比喻为水中的气泡,从水底冒出水面,也就是从下向上开始传播。
onclick() 事件冒泡
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style>
			div {
				padding: 30px;
			}
			#div1 {
				background: red;
			}
			#div2 {
				background: green;
			}
			#div3 {
				background: blue;
			}
		</style>
		<script>
			window.onload = function() {
				//获取各个元素
				var oBody = document.getElementById('body1');
				var oDiv1 = document.getElementById('div1');
				var oDiv2 = document.getElementById('div2');
				var oDiv3 = document.getElementById('div3');
				//对各个元素的单击事件绑定事件处理函数fn1
				window.onclick = fn1;
				document.onclick = fn1;
				oBody.onclick = fn1;
				oDiv1.onclick = fn1;
				oDiv2.onclick = fn1;
				oDiv3.onclick = fn1
				function fn1() { //定义事件处理函数
					console.log(this);
				}
			};
		</script>
	</head>
	<body id="body1">
		<div id="div1">
			<div id="div2">
				<div id="div3"></div>
			</div>
		</div>
	</body>
</html>
点击div3元素,打印信息如下:

说明:onclick单击事件会实现事件冒泡,因此div3元素会首先触发单击事件,所触发的事件仍然会逐级向上传递。
addEventListener() 事件冒泡
addEventListener()方法的第三个参数为false事,为事件冒泡;为true时,为事件捕获。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style>
			div {
				padding: 30px;
			}
			#div1 {
				background: red;
			}
			#div2 {
				background: green;
			}
			#div3 {
				background: blue;
			}
		</style>
		<script>
			window.onload = function() {
				var oDiv1 = document.getElementById('div1');
				var oDiv2 = document.getElementById('div2');
				var oDiv3 = document.getElementById('div3');
				//调用addEventListener()实现事件冒泡
				oDiv1.addEventListener('click', fn1, false);
				oDiv2.addEventListener('click', fn1, false);
				oDiv3.addEventListener('click', fn1, false);
				function fn1() {
					console.log(this);
				}
			};
		</script>
	</head>
	<body id="body1">
		<div id="div1">
			<div id="div2">
				<div id="div3"></div>
			</div>
		</div>
	</body>
</html>
点击div3元素,打印信息如下:

说明:div1、div2和div3元素均使用第三个参数为false的addEventListener()绑定事件函数,因而这3个元素将实现事件冒泡。在Chrome浏览器中运行后,当单击div3时,div3作为事件冒泡的最低层元素,会首先触发单击事件,然后div3逐级向上传递单击事件给div2和div1。
stopPropagation() 阻止事件冒泡
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style>
			#div1 {
				width: 150px;
				height: 150px;
				line-height: 150px;
				text-align: center;
				border: 1px solid silver;
				margin: auto;
				display: none;
			}
		</style>
		<script>
			window.onload = function() {
				var oBtn = document.getElementById("btn");
				var oDiv = document.getElementById("div1");
				oBtn.onclick = function(e) {
					e.stopPropagation(); //阻止事件冒泡
					oDiv.style.display = "block";
				};
				document.onclick = function(e) {
					oDiv.style.display = "none";
				};
			};
		</script>
	</head>
	<body>
		<input id="btn" type="button" value="弹出">
		<div id="div1">
			hello world
		</div>
	</body>
</html>

事件捕获
简介
事件捕获是由Netscape Communicator团队提出来的,从最顶层的window对象开始逐渐往下传播事件,即最顶层的window对象最早接收事件,最低层的具体被操作的元素最后接收事件。

说明:当点击了<div>元素,采用事件捕获,则click事件将按照window -> document -> <html> -> <body> -> <div>的顺序传播。
addEventListener() 事件捕获
使用addEventListener()绑定事件函数时,当第三个参数取值为true时,将执行事件捕获,除此之外的其他事件的绑定方式,都是执行事件冒泡。
因此,只有标准浏览器才能进行事件捕获。
<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			div {
				padding: 40px;
			}
			#div1 {
				background: red;
			}
			#div2 {
				background: green;
			}
			#div3 {
				background: blue;
			}
		</style>
		<script>
			window.onload = function() {
				var oDiv1 = document.getElementById('div1');
				var oDiv2 = document.getElementById('div2');
				var oDiv3 = document.getElementById('div3');
				//事件捕获
				oDiv1.addEventListener('click', fn1, true);
				oDiv2.addEventListener('click', fn1, true);
				oDiv3.addEventListener('click', fn1, true);
				window.addEventListener('click', fn1, true);
				document.addEventListener('click', fn1, true);
				//定义事件函数
				function fn1() {
					console.log(this);
				}
			};
		</script>
	</head>
	<body>
		<div id="div1">
			<div id="div2">
				<div id="div3"></div>
			</div>
		</div>
	</body>
</html>
点击div3元素,打印信息如下:

W3C标准事件流
W3C标准事件流包含3个阶段,捕获阶段、目标阶段、冒泡阶段。
在捕获阶段,事件对象通过目标的祖先从窗口传播到目标的父级。
在目标阶段,事件对象到达事件对象的事件目标。
在冒泡阶段,事件对象以相反的顺序通过目标的祖先传播,从目标的父级开始,到窗口结束。
W3C事件模型中发生的任何事件,先从顶层对象window开始一路向下捕获,直到达到目标元素,其后进入目标阶段。目标元素div接收到事件后开始冒泡到顶层对象window。例如,当用户单击了<div>元素,则首先会进行事件捕获,此时事件按window→document→<html>→<body>的顺序进行传播,当事件对象传到<div>时进入目标阶段,接着事件对象又从目标对象传到body,从而进入事件的冒泡阶段,此时事件对象按<body>→<html>→document→window的顺序传播事件。

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			div {
				padding: 40px;
			}
			#div1 {
				background: red;
			}
			#div2 {
				background: green;
			}
			#div3 {
				background: blue;
			}
		</style>
		<script>
			window.onload = function() {
				var oDiv1 = document.getElementById('div1');
				var oDiv2 = document.getElementById('div2');
				var oDiv3 = document.getElementById('div3');
				//标准事件流处理事件
				oDiv1.addEventListener('click', function() {
					console.log('事件冒泡1');
				}, false);
				oDiv1.addEventListener('click', function() {
					console.log('事件捕获1');
				}, true);
				oDiv2.addEventListener('click', function() {
					console.log('事件冒泡2');
				}, false);
				oDiv2.addEventListener('click', function() {
					console.log('事件捕获2');
				}, true);
				oDiv3.addEventListener('click', function() {
					console.log('事件捕获3');
				}, true);
				oDiv3.addEventListener('click', function() {
					console.log('事件冒泡3');
				}, false);
			};
		</script>
	</head>
	<body>
		<div id="div1">
			<div id="div2">
				<div id="div3"></div>
			</div>
		</div>
	</body>
</html>
点击div3元素,打印信息如下:

取消事件默认行为
事件的默认行为指的是:当一个事件发生时,浏览器自己会默认做的事情。这些事件的默认行为,在某些情况下,可能并不是我们所期望的,此时就需要取消它。事件默认行为的取消方法跟事件的绑定方式有关。
一、使用对象的事件属性绑定事件(即使用“obj.on事件名称=事件处理函数”的绑定格式)的事件默认行为的取消方法是:在当前事件的处理函数中return false即可阻止当前事件的默认行为。
二、使用addEventListenter()绑定事件函数的事件默认行为的取消方法是:在当前事件的处理函数中使用event.preventDefault()即可阻止当前事件的默认行为。
取消使用对象属性绑定的事件的默认行为
<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title>取消使用对象属性绑定的事件的默认行为</title>
		<script>
			window.onload = function() {
				var oBtn = document.getElementById('btn');
				oBtn.onclick = function() {
					var name = document.getElementById("username");
					if (name.value.length == 0) {
						alert("请输入姓名");
						return false; //用户名没有输入时,阻止表单提交
					}
				};
			};
		</script>
	</head>
	<body>
		<form action="new_file.html">
			姓名: <input type="text" name="username" id="username" />
			<input type="submit" value="提交" id='btn' />
		</form>
	</body>
</html>
取消使用addEventListener()绑定的事件的默认行为
<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title>取消使用addEventListener()绑定的事件的默认行为</title>
		<script>
			window.onload = function() {
				var oBtn = document.getElementById('btn');
				oBtn.addEventListener('click', function(ev) {
					var ev = ev || event;
					var name = document.getElementById("username");
					if (name.value.length == 0) {
						alert("请输入姓名");
						if (ev.preventDefault) { //用户名没有输入时,阻止表单提交
							ev.preventDefault();
						}
					}
				}, false);
			};
		</script>
	</head>
	<body>
		<form action="new_file.html">
			姓名: <input type="text" name="username" id="username" />
			<input type="submit" value="提交" id='btn' />
		</form>
	</body>
</html>
案例
利用事件冒泡实现分享功能
<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title>使用事件冒泡实现"分享"功能</title>
		<style>
			#div1 {
				width: 80px;
				height: 150px;
				border: black 1px solid;
				position: absolute;
				left: -82px;
				top: 100px;
			}
			#div2 {
				width: 30px;
				height: 70px;
				position: absolute;
				right: -30px;
				top: 45px;
				background: black;
				color: white;
				text-align: center;
			}
			ul {
				list-style: none;
				padding: 0 20px;
			}
			img {
				width: 36px;
				height: 39px;
			}
		</style>
		<script>
			window.onload = function() {
				var oDiv = document.getElementById('div1');
				oDiv.onmouseover = function() { //鼠标光标移入,使div1显示
					this.style.left = '0px';
				}
				oDiv.onmouseout = function() { //鼠标光标移出,使div1隐藏
					this.style.left = '-82px';
				}
			};
		</script>
	</head>
	<body>
		<div id="div1">
			<ul>
				<a href="#">
					<li><img src="img/apple_pic.png" /></li>
				</a>
				<a href="#">
					<li><img src="img/banana_pic.png" /></li>
				</a>
				<a href="#">
					<li><img src="img/cherry_pic.png" /></li>
				</a>
			</ul>
			<div id="div2">分享到</div>
		</div>
	</body>
</html>
 
 



















