13 事件

历史:

  • IE3和Netscape Navigator2 : 作为分担服务器负载的一种手段;
  • IE4和Naviscape4 : 提供了相似却不相同的API;
  • DOM2规范制定 : 开始尝试标准化DOM事件;
  • DOM2实现 : IE9、Firefox、Opera、Safari和Chrome全部实现‘DOM2级事件’核心部分;

    + DOM3级出现 : API变得更加繁琐。

    13.1 事件流

    13.1.1 事件冒泡 : 最具体的元素->…->document

    Alt text
    支持情况: 所有浏览器。
浏览器 表现
IE5.5— 最具体的元素->…->body->document
IE9、Firefox、Chrome、Safari 最具体的元素->…->body->html->document->window

13.1.2 事件捕获 : document->html->body->…->最具体的元素

Alt text
说明:DOM2级规范

  • 支持情况:IE9、Safari、Chrome、Opera、Firefox
  • 不支持情况: 所有老版本浏览器

    13.1.3 DOM事件流

    支持情况: IE9、Safari、Chrome、Opera、Firefox
  1. 事件捕获阶段: 为截获事件提供机会
  2. 处于目标阶段: 实际的目标接收到事件
  3. 事件冒泡阶段: 冒泡阶段
    Alt text

    13.2 事件处理程序

    13.2.1 HTML事件处理程序

    特点
  • 会创建一个封装着元素属性值的函数
  1. this : 当前dom
  2. event : 事件对象
  • 扩展了作用域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//形象说明作用域的扩展情况
function(){
with(document){
with(this){
//HTML标签中的代码相当于在这里执行
}
}
}
//表单的情况
function(){
with(document){
with(this.form){
with(this){
//HTML标签中的代码相当于在这里执行
}
}
}
}

方式一 : 直接在标签中嵌入JS代码
注意:不能使用未经转义的HTML语法字符!

1
<input type='button' value='Click Me' onclick="alert('Clicked')" />

方式二 : 调用其他地方定义的脚本

1
2
3
4
5
6
<script>
function showMessage(){
alert('Hello world!');
}
</script>

<input type='button' value='Click Me' onclick="showMessage()" />

13.2.2 DOM0级事件处理程序 : 将函数赋值给一个事件处理程序属性

说明

  • DOM0级方法指定的事件处理程序被认为是元素的方法,因此程序中的this引用当前元素;
  • 这种事件处理程序在事件流的冒泡阶段处理;
  • 每个元素(包括window和document)都有自己的的事件处理程序。
1
2
3
4
5
var btn = document.getElementById('myBtn');
btn.onclick = function(){
alert(this.id); //'myBtn'
};
btn.onclick = null; //删除通过DOM0级方法指定的事件处理程序

13.2.3 DOM2级事件处理程序

兼容性:IE9 Firefox Safari Chrome Opera

####addEventListener()
说明: 添加事件,3个参数,要处理的事件名、作为事件处理处理程序的函数、布尔值(true表示捕获阶段;false表示冒泡阶段)

  • 依附元素的作用域
  • 可以添加多个事件处理程序,事件触发后按添加的顺序执行
  • addEventListener()添加的事件处理程序只能使用removeEventListener()来移除
  • 移除时传入的参数与添加处理程序使用相同的参数
  • 添加的匿名函数无法移除
    ####removeEventListener()
    说明:移出addEventListener()添加的事件处理程序,参数和 addEventListener() 保持一致
    注意: 将事件添加到事件的冒泡阶段而不是捕获阶段可以最大程度兼容各种浏览器,除非需要在事件到达目标之前截获事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var btn = document.getElementById('myBtn');
//添加多个事件处理程序
btn.addEventListener('click', function(){
alert(this.id);
},false);
btn.addEventListener('click', function(){
alert('Hello World!');
},false);
//演示移除事件处理程序
var handler = function(){
alert(this.id);
};
btn.addEventListener('click', handler, false);
btn.removeEventListener('click', handler, false);

13.2.4 IE事件处理程序

注意:该方法没有考虑只支持DOM0级浏览器只支持一个事件处理程序的问题,如果多次绑定处理程序,只有最后一个有效。

####attachEvent()
说明:添加事件,两个参数,事件处理程序名称、事件处理函数

  • IE8-只支持事件冒泡,因此会被添加到冒泡阶段
  • 事件名带on前缀
  • 事件处理程序在全局作用域中运行,this等于window
  • 可以添加多个事件处理程序,事件触发后按与添加的相反的顺序执行
  • 移除时传入的参数与添加处理程序使用相同的参数
  • 添加的匿名函数无法移除
  • attachEvent添加的事件处理程序只能使用detachEvent移除
  • ####detachEvent()
    说明:移除通过attachEvent()添加的事件处理函数
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
32
33
34
35
36
var btn = document.getElementById('myBtn');
var handler = function(){
alert(this == window); //true
};
btn.attachEvent('onclick', handler);
btn.detachEvent('onclick', handler);
IE Opera
13.2.5 跨浏览器的事件处理程序
/**
* DOM2>IE>DOM0
* param{object} element - dom节点对象
* param{string} type - 事件名称
* param{boolean} handler - 函数的引用
*/

var EventUtil = {
//添加事件处理程序
addHandler: function(element, type, handler){
if(element.addEventListener){ //DOM2
element.addEventListener(type, handler, false);
}else if(element.attachEvent){ //IE8---
element.attachEvent('on'+type, handler);
}else{ //DOM0
element['on'+type] = hanler;
}
},
//移除事件处理程序
removeHandler: function(element, type, handler){
if(element.removeEventListener){ //DOM2
element.addEventListener(type, handler, false);
}else if(element.detachEvent){ //IE8---
element.detachEvent('on'+type, handler);
}else{ //DOM0
element['on'+type] = null;
}
}
};

13.3 事件对象

说明: 触发DOM上的某个事件是会产生一个事件对象event(DOM0或DOM2),包含所有与时间有关的信息。
特点

  • 所有浏览器都支持event对象,但支持方式不同
  • 只在事件处理程序执行期间存在,执行完毕后被销毁
  • 不同事件类型可用的属性和方法不同,都包括的成员如下
    Alt text
    Alt text

    • event.type : 事件类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var btn = document.getElementById('myBtn');
var handler = function(event){
switch(event.type){
case "click":
alert('Clicked');
break;
case "mouseover":
event.target.style.backgroundColor = 'red';
break;
case "mouseout":
event.target.style.backgroundColor = '';
break;
}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
  • event.target: 事件的实际目标(最具体的那个元素)
  • event.currentTarget: 和this相同,注册事件的那个元素
  • event.eventPhase :事件当前所在的事件流的阶段
  1. 捕获阶段调用事件处理程序
  2. 事件处理程序处在目标对象上
  3. 冒泡阶段调用事件处理程序
1
2
3
4
5
6
7
8
9
10
11
12
13
var btn = document.getElementById('myBtn');
//捕获阶段
document.body.addEventListener('click', function(event){
alert(event.eventPhase); //1
},true);
//处于目标阶段
btn.onclick = function(event){
alert(event.eventPhase); //2
};
//冒泡阶段
document.body.addEventListener('click', function(event){
alert(event.eventPhase); //3
},false);
  • event.preventDefault() : 取消默认行为
  • event.stopPropagation() : 立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡

13.3.2 IE中的事件对象

说明:访问IE中的event对象的方式取决于指定事件处理程序的方法

####window.event(DOM0级方法)

1
2
3
4
5
var btn = document.getElementById('myBtn');
btn.onclick = function(){
var event = window.event;
alert(event.type); //'click'
};

####作为参数对象(attachEvent())

1
2
3
4
var btn = document.getElementById('myBtn');
btn.attachEvent('onclick', function(event){
alert(event.type); //'click'
});

####直接访问event(HTML中)

1
<input tyep='button' value='Click Me' onclick='alert(event.type)' />

Alt text

13.3.3 跨浏览器的事件对象

说明:创建一个兼容的操作事件对象的工具对象:因为兼容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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
var EventUtil = {
/**
* 用来添加事件处理程序的方法
* param{object} element - dom
* param{string} type - 事件名称
* param{function} handler - 函数引用
*/

addHandler: function(element, type, handler){
if(element.addEventListener){ //DOM2
element.addEventListener(type, handler, false);
}else if(element.attachEvent){ //IE8---
element.attachEvent('on'+type, handler);
}else{ //DOM0
element['on'+type] = hanler;
}
},
/**
* 用来移除事件处理程序的方法
* param{object} element - dom
* param{string} type - 事件名称
* param{function} handler - 函数引用
*/

removeHandler: function(element, type, handler){
if(element.removeEventListener){ //DOM2
element.addEventListener(type, handler, false);
}else if(element.detachEvent){ //IE8---
element.detachEvent('on'+type, handler);
}else{ //DOM0
element['on'+type] = null;
}
},
/**
* 获得事件对象的方法
* param{object} event - 事件处理程序执行时产生的事件对象(如果有的话)
* return{object} 事件对象
*/

getEvent: function(event){
return event ? event : window.event;
},
/**
* 获得触发事件的目标的方法
* param{event} event - 事件对象
* return{object} dom - 触发事件的节点
*/

getTarget: function(event){
return event.target || event.srcElement;
},
/**
* 取消默认动作
* param{object} event -事件对象
*/

preventDefault: function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
},
/**
* 阻止事件冒泡(或捕获)
* param{object} event -事件对象
*/

stopPropagation: function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
};
使用上述快跨览器的工具
btn.onclick = function(event){
event = EventUtil.getEvent(event); // 确保在不同浏览器都能获得event
var target = EventUtil.getTarget(event); //确保获得target
EventUtil.preventDefault(event); //确保清除默认动作
EventUtil.stopPropagatiom(event); //阻止传播
};

13.4 事件类型

  • DOM2级事件
  • DOM3级事件(以DOM2为基础)
  • UI事件
  • 焦点事件
  • 鼠标事件
  • 滚轮事件
  • 文本事件
  • 键盘事件
  • 合成事件
  • 变动事件
  • 变动名称事件

  • HTML5定义的一组事件

  • DOM和BOM中实现的其它专有事件(没有规范)

13.4.1 UI事件

历史:出现在DOM规范之前,被规范保留。
分类:现有的UI事件




















事件名称DOM触发时机备注
DOMActive 任何元素元素已经被用户操作激活被DOM3废弃
loadwindow页面加载完后HTML事件
框架集所有框架都加载完毕
<img>图像加载完毕
<object>嵌入的内容加载完毕
unloadwindow页面完全卸载HTML事件
<img> 无法加载图片
框架集 所有框架都卸载
<object> 嵌入的内容卸载完毕
abort<object> 用户停止下载,嵌入的内容没有加载完HTML事件
errorwindowJavaScript错误HTML事件
<img>无法加载图像
<object>无法加载嵌入内容
框架集有框架无法加载
select<input>用户选择文本框一个或多个字符HTML事件
<textarea>用户选择文本框一个或多个字符
resizewindow或框架窗口或框架变化HTML事件
scroll带滚动条的元素用户滚动带滚动条的元素中的内容HTML事件<body>元素中包含加载元素的滚动条

####为UI事件定义事件处理程序
#### 13.4.1.1 load事件
案例一:以body为例
方式一: JS(推荐)

+ 使用了跨浏览器的脚本;
+ 传入的event不包含有关这个时间的任何附加信息;
+ 兼容DOM时,event.target会被设置为document;IE不会为其设置srcElement属性;
+ “DOM2级事件”规范应该在document上而不是window上触发load事件,但所有浏览器都在window上面实现了该事件(确保向后兼容)。

1
2
3
EventUtil.addHandler(window, 'load', function(event){
alert('Loaded!');
});


方式二: 为元素添加onload属性

1
2
3
4
5
6
7
8
<!DOCTYPE html>
<html>
<head>
<title>Load Event Example</title>
</head>
<body onload='alert('Loaded!')'>
</body>
</html>


案例二:img
方式一

1
2
3
4
5
var image = document.getElementById('myImage');
EventUtil.addHandler(image, 'load', function(event){
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
});


方式二

1
<img src='smile.gif' onload='alert('Image loaded.')'>


案例三:创建新的 <img>元素,同时指定一个事件处理程序

+ 要在window上的onload事件触发后才添加DOM中,否则document.body会报错;
+ 一旦设置了src属性,新创建的图像就开始加载图像,和是否添加到文档中无关;

方式一: DOM的方式
注意:[IE8-]没有添加到DOM中的节点触发load事件时不会生成event对象。

1
2
3
4
5
6
7
8
9
EventUtil.addHandler(window, 'load', function(event){
var image = document.createElement('img');
EventUtil.addHandler(image, 'load', function(event){
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
});
document.body.appendChild(image);
image.src = 'smile.gif';
});


方式二: Image对象

+ 可以像使用<img>元素一样使用Image对象(并非所有浏览器都将Image对象实现为<img>);
+ 无法添加到DOM中;
+ 【IE8- 】Image对象触发load事件不会生成event对象。

1
2
3
4
5
6
EventUtil.addHandler(window, 'load', function(){
var image = new Image();
EventUtil.addHandler(image, 'load', function(event){
alert('Imaeg loaded!');
});
});


案例四: script元素
说明:指定src属性并将元素添加到文档后才开始下载。
兼容性问题

|浏览器版本|script元素onload事件|event.target|
|—|—|—|
|大多数浏览器|支持|