skip to content
寻找莉莉丝

JavaScript 的事件流

/ 6 min read / 次阅读

一、前言

事件就是文档或者浏览器窗口中发生的一些特定的交互瞬间。我们可以用侦听器(或者事件处理程序)来预定事件,这样当监测到事件发生时就能执行响应的代码了。

二、事件

  1. 事件是JS引擎内置的、预先定义的函数变量
  2. 事件有可能由浏览器触发,也可能由用户触发
  3. 当事件触发时,JS引擎会按照一定的规则调用这些变量中的函数
  4. 事件可编程

三、事件绑定

1. 第一种

onType = function (e) {
	// more codes
};

特点:浏览器兼容性好

缺点:过于老旧,只能绑定一个函数,等同于写在DOM上的attribute

注意:Type代表事件类型

2. 第二种

eventTarget.addEventListener(
	Type,
	function () {
		// more codes
	},
	true / false,
);

特点:可以绑定多个函数,同一个函数只能绑定一次

缺点:IE9及以下不支持

注意:事件监听函数的第三个参数,如果是true代表在捕获阶段调用该事件处理程序,false代表在冒泡阶段调用事件处理程序。

3. 第三种

element.attachEvent(onType, function () {
	// more codes
});

优点:可以绑定多个函数,同一函数可以绑定多次

缺点:只有IE支持此标准

四、事件解绑

分别对应以上三种绑定方式的解绑方法:

  1. onType = null;
  2. eventTarget.removeEventListener(Type, function() {…}, true/false);
  3. element.detachEvent(onType, function() {…});

五、事件流

DOM的事件流分为三个阶段:

  1. 捕获阶段:事件从Document节点自上而下向目标节点传播的阶段(1-4)
  2. 目标阶段:真正的目标节点正在处理事件的阶段(4-6)
  3. 冒泡阶段:事件从目标节点自上而下向Document节点传播的阶段(6-10)

注意:DOM事件的触发顺序是:首先事件捕获,然后是事件处理执行,最后是事件冒泡。

六、取消冒泡事件

1. 方式

  1. W3C:event.stopPropagation();
  2. IE&Chrome: e.cancelBubble = true;

2. 案例

1. 事件绑定,返回事件源

这里默认为false,在冒泡阶段执行事件处理程序。

<!doctype html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta http-equiv="X-UA-Compatible" content="ie=edge" />
		<title>js事件流</title>
		<style>
			#outer {
				border: 2px solid red;
				padding: 20px;
			}
			#box {
				border: 2px solid green;
				padding: 20px;
			}
			#myDiv {
				border: 1px solid #000;
				text-align: center;
				width: 100%;
				height: 100%;
			}
		</style>
	</head>
	<body>
		<div id="outer">
			outer
			<div id="box">
				box
				<div id="myDiv">myDiv</div>
			</div>
		</div>
		<script>
			var outer = document.getElementById("outer");
			var box = document.getElementById("box");
			var myDiv = document.getElementById("myDiv");

			outer.addEventListener(
				"click",
				function (e) {
					console.log("1. outer 冒泡");
					e = e || window.event; // 后一种为兼容IE的写法
					var target = e.target || e.srcElement;
					console.log(target); // 返回目标元素(事件源)
				},
				false,
			);

			box.addEventListener(
				"click",
				function (e) {
					console.log("2. box 冒泡");
					e = e || window.event;
					var target = e.target || e.srcElement; // 后一种为兼容IE的写法
					console.log(target);
				},
				false,
			);

			myDiv.addEventListener(
				"click",
				function (e) {
					console.log("3. myDiv 冒泡");
					e = e || window.event;
					var target = e.target || e.srcElement;
					console.log(target);
				},
				false,
			);
		</script>
	</body>
</html>
1.1 点击myDiv区域

解析:冒泡顺序:myDiv => box => outer => document => window;事件源为myDiv。

1.2 点击box区域

解析:冒泡顺序:box => outer => document => window;事件源为box。

1.3 点击outer区域

解析:冒泡顺序:outer => document => window;事件源为outer。

2. 取消冒泡事件

这里试着取消box的冒泡事件。 当我们点击box区域时,应该仅仅返回“2. box 冒泡”的打印结果。

box.addEventListener(
	"click",
	function (e) {
		console.log("2. box 冒泡");
		e = e || window.event;
		var target = e.target || e.srcElement; // 后一种为兼容IE的写法
		console.log(target);

		// 冒泡事件取消
		if (e.stopPropagation) {
			// W3C标准
			e.stopPropagation();
		} else {
			e.cancelBubble = true; // IE & Chrome支持
		}
	},
	false,
);
2.1 点击box区域

结果显示,取消box的冒泡事件成功。

七、默认事件

我们知道在点击某些控件或者元素时,会出现刷新页面的效果,这些事件就是默认事件。 典型的默认事件有:

  1. 表单提交
  2. a标签的跳转
  3. 点击右键弹出菜单

八、取消默认事件

在我们开发的过程中,我们往往不需要这些触发的默认事件。那么如何取消呢?

1. 方式

  1. onType: return false;
  2. W3C: event.preventDefault();
  3. IE: event.returnValue = false;

2. 案例

这里以取消右键菜单的默认事件为例。

1. 第一种方式

document.oncontextmenu = function () {
	console.log("right click");
	return false;
};

2. 第二种方式

document.addEventListener(
	"contextmenu",
	function (e) {
		console.log("addEventListener contextmenu");
		e = e || window.event;
		if (e.preventDefault) {
			e.preventDefault();
		} else {
			e.returnValue = false;
		}
	},
	false,
);

九、本节思维导图