事件
本章内容 (p363-p429)
- 理解事件流
- 使用事件处理程序
- 不同的事件类型
事件流
事件流描述的是从页面接收事件的顺序。但是IE 和 Netscape 开发团队提出了相反的事件流感念,IE的事件流是事件冒泡流,而Netscape 的事件流是事件捕获流。
DOM2级事件规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段
DOM0级事件处理程序
1 | var btn = document.getElementById("myBtn") |
DOM2级事件处理程序
定义了两个方法,用于处理制定和删除事件程序的操作:addEventListener() 和 removeEventListener()。所有DOM节点都包含这两个方法,并且都接受3个参数:
- 要处理的事件名
- 作为事件处理程序的函数
- 一个布尔值(true表示在捕获阶段调用,false表示在冒泡阶段)
1
2
3
4
5//该事件会再冒泡阶段被触发
var btn = document.getElementById("myBtn")
btn.addEventListener("click",function(){
alert(this.id)
},false)
使用DOM2级方法的除妖好处是可以添加多个事件处理程序,多个程序会按添加顺序触发1
2
3
4
5
6
7
8
9var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert(this.id;)
},false)
btn.addEventListener("click",function(){
alert("Hello world");
},false)
通过addEventListener()添加的事件只能通过removeEventLisener() 来移除,移除时传入的参数与添加时候的参数相同,以为着通过addEventListener()添加的匿名函数将无法移除。
1 | //以下移除方法removeEventLisener()无效,因为第二个参数是一个完全不同的函数 |
如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序。大多数情况下都是在冒泡阶段,可以最大限度地兼容各种浏览器
IE事件处理程序
….
跨浏览器的事件处理程序
要保证处理事件的代码在大多数浏览器下一致地运行,只需关注冒泡阶段。
(以下代码最好记下来)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32var EventUtil = {
addHandler: funciton(element, type, handler){
if(element.addEventListener){
element.addEventListener(type, handler, false)
}else if(element.attachEvent){
element.attachEvent('on'+type, handler)
}else {
element['on'+type] = handler;
}
}
removeHandler: function(element, type ,handler){
if(element.removeEventListener){
element.removeEventListener(type, handler, false)
}else if(element.datachEvent){
element.datachEvent('on'+type, handler)
}else {
element['on'+type] = null
}
}
};
//以下是调用方式
var btn = document.getElementById("myBtn")
var handler = function(){
alert("Cliked")
};
EventUtil.addHandler(btn, "click", handler)
//这里省略了其他代码
EventUtil.removeHandler(btn, "click", handler)
事件对象event
触发DOM上的某个事件时,会产生一个事件对象event,包含与事件有关的信息。
常用的属性方法:
属性/方法 | 说明
—|—
currentTarget | 其事件处理程序当前正在处理事件的那个元素
target | 事件的目标
preventDefault() | 取消事件的默认行为
stopPropagation() | 取消事件的进一步捕获或冒泡,同时组织任何事件处理程序被调用
currentTarget 和 target 的区别
在事件处理程序内部,this始终等于currentTartget的值,而target则只包含事件的实际目标。
1 | // 如果直接将事件处理程序制定给了缪奥元素,则this、currentTarget和terget包含相同的值 |
preventDefault() 取消默认行为
1 | var link = document.getElementById("myLink") |
stopPropagation() 立即停止事件在DOM层次中的传播,取消进一步的事件捕获或冒泡
1 | var btn = document.getElementById("myBtn") |
eventPhase 属性 判断事件处于哪个阶段
事件类型
- UI事件
- load:当页面完全加载后在window上面触发
- error:当发生js错误时在window上面触发
- select:当用户选择文本框中的一或多个字符时触发
- resize:当窗口或框架的大小变化时在window或框架上面触发
- scroll:当用户滚动带滚动条的元素中的内容时,在该元素上面触发
- 焦点事件
- 鼠标事件
- 滚轮事件
- 文本事件
- 键盘事件
- 合成事件
- 变动事件(当底层DOM结构发生变化时触发)
load 图片懒加载
事件委托
对“事件处理程序过多”的解决方案就是事件委托。事件委托利用了事件冒泡,制定一个事件处理程序,就可以管理某一类型的所有事件。1
2
3
4
5
6// html
<ul id = "myLinks">
<li id="goSomewhere"> Go Somewhere</li>
<li id="doSomething"> Do Something</li>
<li id="sayHi"> Say Hi</li>
</ul>
按照传统的方法,要为他们添加3个事件1
2
3
4
5
6
7
8
9
10
11
12
13
14var item1 = document.getElementById("goSomewhere")
var item2 = document.getElementById("doSomething")
var item3 = document.getElementById("sayHi")
EventUtil.addHandler(item1,"click",function(event){
location.href = 'http://www.wrox.com'
})
EventUtil.addHandler(item2,"click",function(event){
document.title = "I changed the document's title "
EventUtil.addHandler(item3,"click",function(event){
alert("hi")
})
使用事件委托,只需要在DOM树中尽量最高的层次上添加一个事件处理程序1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var list = document.getElementById("myLinks")
EventUtil.addHandler(list,'click',function(event){
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
switch(target.id){
case "doSomething":
document.title = "I changed the document's title "
break;
case "goSomewhere":
location.href = 'http://www.wrox.com'
break;
case "sayHi":
alert("hi")
break;
}
})
事件委托的优点是需要占用的内存更少,对DOM的操作更少。