快速理解Event事件
浏览器事件是所有web程序的核心。javascript与HTML之间的交互是通过事件实现的。通过这些事件我们定义将要发生的行为。事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信。
1.事件流
一件事情发生后,在DOM节点之间传播的阶段,在DOM2级事件中包括三个阶段:
- 捕获阶段(capture phase)
- 目标阶段(target phase)
- 冒泡阶段(bubbling phase)
(1)事件捕获
事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。
示例
<div>click me</div>
如果你点击了上面的div元素,那么会以下面的顺序触发click事件。
document > html > body > div
(2)事件冒泡
事件冒泡与事件捕获相反,它由最具体的元素(一般是嵌套最深的那个节点)开始接收,然后到不具体的元素节点文档。
<div>click me</div>
如果你点击了上面的div元素,那么会以下面的顺序触发click事件。
div > body > html > document
完整事件流实例:(来源:事件模型)
<div>
<p>Click Me</p>
</div>
如果对这两个节点的click事件都设定监听函数,则click事件会被触发四次。
var phases = {
1: 'capture',
2: 'target',
3: 'bubble'
};
var div = document.querySelector('div');
var p = document.querySelector('p');
div.addEventListener('click', callback, true);
p.addEventListener('click', callback, true);
div.addEventListener('click', callback, false);
p.addEventListener('click', callback, false);
function callback(event) {
var tag = event.currentTarget.tagName;
var phase = phases[event.eventPhase];
console.log("Tag: '" + tag + "'. EventPhase: '" + phase + "'");
}
// 点击以后的结果
// Tag: 'DIV'. EventPhase: 'capture'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'DIV'. EventPhase: 'bubble'
上面代码表示,click事件被触发了四次:<p>节点的捕获阶段和冒泡阶段各1次,<div>节点的捕获阶段和冒泡阶段各1次。
2事件处理程序(事件监听程序)
事件处理程序是指事件发生时,程序要执行的函数。DOM提供三种方法,可以用来为事件绑定监听函数。
(1)HTML事件处理程序 (HTML标签的on-属性)
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML属性来指定。
<input type="button" value="clickMe" onclick="alert("Clicked!")">
(2)DOM0级事件处理程序 (Element节点的事件属性)
通过JavaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
注意:以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
window.onload=function(){
alert("clicked!");
}
(3)DOM2级事件处理程序
DOM2级事件处理程序定义了两个方法用于处理指定和删除事件处理程序的操作:
addEventListener();和removeEventListener();
所有DOM节点中都包含这两个方法,并且他们都接受3个参数:
- 要处理的事件名,
- 事件处理程序函数,
- 布尔值(如果为true,表示在捕获阶段调用事件处理程序;如果为false,表示在冒泡阶段调用事件处理程序。)
btn.addEventListener("click",function(){
alert(this.id);
},false);
三种方法对比总结:
-
第一种:违反了HTML与JavaScript代码相分离的原则;
-
第二种:同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。
-
第三种(推荐):可以针对同一个事件,添加多个监听函数。
能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发回监听函数。
除了DOM节点,还可以部署在window、XMLHttpRequest等对象上面,等于统一了整个JavaScript的监听函数接口。
3.事件代理或者事件委托(Event Delegation)
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,而不是给每一个子元素绑定事件(太麻烦了,如果添加新的子元素,还得改代码)通过事件代理(delegation)方法,绑定容器就可以监听所有子元素了。
//处理列表
var ul = document.querySelector('ul');
ul.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() === 'li') {
// some code
}
});
//处理表格
var myTable = document.getElementById('my-table');
myTable.onclick = function () {
// 处理浏览器兼容
e = e || window.event;
var targetNode = e.target || e.srcElement;
// 测试如果点击的是TR就触发
if (targetNode.nodeName.toLowerCase() === 'tr') {
alert('You clicked a table row!');
}
}
4.事件对象
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素event.target,事件的种类event.type,以及与特定事件相关的信息。
下面是事件对象的属性和方法
5.事件类型(常用的)
鼠标事件
‘mousedown’ – 鼠标设备按下一个元素的时候触发mousedown事件。
‘mouseup’ – 鼠标设备从按下的元素上弹起的时候触发mouseup事件。
‘click’ – 鼠标点击元素的时候触发click事件。
‘dblclick’ – 鼠标双击元素的时候触发dblclick事件。
‘mouseover’ – 鼠标移动到某元素上的时候触发mouseover事件。
‘mouseout’ – 鼠标从某元素离开的时候触发mouseout事件。
‘mousemove’ – 鼠标在某元素上移动但未离开的时候触发mousemove事件。
键盘事件
‘keypress’ – 按键按下的时候触发该事件。
‘keydown’ – 按键按下的时候触发该事件,并且在keypress事件之前。
‘keyup’ – 按键松开的时候触发该事件,在keydown和keypress事件之后。
表单事件
‘select’ – 文本字段(input, textarea等)的文本被选择的时候触发该事件。
‘change’ – 控件失去input焦点的时候触发该事件(或者值被改变的时候)。
‘submit’ – 表单提交的时候触发该事件。
‘reset’ – 表单重置的时候触发该事件。
‘focus’ – 元素获得焦点的时候触发该事件,通常来自鼠标设备或Tab导航。
‘blur’ – 元素失去焦点的时候触发该事件,通常来自鼠标设备或Tab导航。
其它事件
‘load’ – 页面加载完毕(包括内容、图片、frame、object)的时候触发该事件。
‘resize’ – 页面大小改变的时候触发该事件(例如浏览器缩放)。
‘scroll’ – 页面滚动的时候触发该事件。
‘unload’ – 从页面或frame删除所有内容的时候触发该事件(例如离开一个页面)。
6补充:跨浏览器的事件处理程序与对象
之所以会存在跨浏览器的处理程序与对象,主要是因为IE的特殊。
(1)IE中使用attachEvent()事件处理程序
(2)IE中使用window.event获得对象
为了兼容性,需要编写跨浏览器的事件处理程序与对象。详细见JavaScript高级程序设计讲解。