event | 事件
事件 & 事件流
事件是可以被 JavaScript 侦测到的行为。
鼠标点击、鼠标移动、鼠标滚动、按下键盘,浏览器窗口大小的改变,网页加载完成,关闭网页等等都会发生事件。
事件流有两种:
- 事件冒泡
IE的事件流叫事件冒泡,即事件开始时由最具体的元素(文档中嵌套层次最深的节点)接收,然后逐级向上传播到较为不具体的节点。 - 事件捕获
Netscape团队提出的另一种事件流叫事件捕获,事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。
一个DOM事件分为三个阶段
- 事件捕获阶段(capture phase)
- 处于目标阶段(target phase)
- 事件冒泡阶段(bubble phase)

事件捕获阶段为事件的触发奠定了基础,当DOM事件发生的时候,首先由最不具体的
window结点向下捕获那个具象元素(触发事件的元素),事件捕获之后就开始执行绑定在上面的函数;当函数执行完毕,触发事件冒泡进入冒泡阶段,一直从触发的元素逐级想上传递,直至window元素。
事件模型
- 原始事件模型(DOM0级)
- 标准事件模型(DOM2级)
- IE事件模型
原始事件模型(DOM0级)
HTML 代码中直接绑定
<button onclick="alert('click')">click</button>通过 JavaScript 代码绑定
var btn = document.getElementById('btn'); btn.onclick = function() { alert('click'); }移除事件
var btn = document.getElementById('btn'); btn.onclick = null;特性
- 绑定速度快
DOM0 级事件具有很好的跨浏览器优势,会以最快的速度绑定,但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行
- 只能绑定一个事件处理函数
当希望为同一个元素绑定多个同类型事件的时候,后面的事件会覆盖前面的事件
- 只支持冒泡,不支持捕获
- 绑定速度快
标准事件模型(DOM2级)
三个过程:
- 事件捕获阶段
从document一直向下传播到目标元素, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行 - 处于目标阶段
到达目标元素, 触发目标元素的监听函数 - 事件冒泡阶段 从目标元素冒泡到
document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行
两个方法:
1 . addEventListener -> 添加事件侦听器
2 . removeEventListener -> 移除事件侦听器
/**
* @param {String} eventType 指定事件类型(不要加on -> 'click')
* @param {Function} handler 事件处理函数
* @param {Boolean} useCapture 是否在捕获阶段触发事件处理函数,一般设置为false与IE浏览器保持一致
*
* */
var btn = document.getElementById('.btn');
// 添加事件侦听器
btn.addEventListener(eventType, handler, useCapture);
// 移除事件侦听器
btn.removeEventListener(eventType, handler, useCapture);
特性:
- 可以绑定多个事件处理函数
- 当第三个参数(useCapture)设置为true就在捕获过程中执行,反之在冒泡过程中执行处理函数
- 事件处理函数的
this指向触发事件的元素
IE事件模型
两个过程:
- 事件处理阶段
到达目标元素, 触发目标元素的监听函数。 - 事件冒泡阶段
从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
两个方法:
attachEvent-> 绑定监听函数detachEvent-> 移除监听函数
/**
* @param {String} eventType 指定事件类型(带on -> 'onclick')
* @param {Function} handler 事件处理函数
*
* */
var btn = document.getElementById('.btn');
// 添加事件侦听器
btn.attachEvent(eventType, handler);
// 移除事件侦听器
btn.detachEvent(eventType, handler);
事件代理(Event delegation)
事件代理也叫事件委托,是指将事件绑定到目标元素的父元素上,然后通过事件冒泡机制触发该事件。
<div id="box">
<input type="button" value="按钮" id="btn">
<input type="button" value="按钮2" id="btn2">
<input type="button" value="按钮3" id="btn3">
</div>
<script>
// 直接通过父节点一次性为所有子结点注册监听函数:
var box = document.getElementById('box');
box.onclick = function(e) {
var e = e || window.event;
var target = e.target || e.srcElement;
if (target.nodeName.toLowerCase() === 'input') {
alert(target.value);
}
}
// target 返回触发事件的元素,不一定是绑定事件的元素
// currentTarget 返回的是绑定事件的元素
</script>
优点:
- 减少内存消耗,提高性能
每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
- 动态监听事件
当新增子元素时,无需再次为新增元素绑定事件,因为事件是绑定在父元素上的,所以新增元素也会有相同的事件。
阻止冒泡/默认行为
// 阻止事件冒泡
function stopPropagation(e) {
e = e || window.event;
if(e.stopPropagation) {
e.stopPropagation(); //W3C阻止冒泡方法
} else {
e.cancelBubble = true; //IE阻止冒泡方法
}
}
// 阻止默认行为
function preventDefault(e) {
e = e || window.event;
if(e.preventDefault) {
e.preventDefault(); //W3C阻止默认行为
} else {
e.returnValue = false; //IE阻止默认行为
}
}
child.onclick = function (e) {
alert("你点击了child区域");
stopPropagation(e);
preventDefault(e);
};