红宝书学习:第十七章 事件

本章内容:

  • 事件流:冒泡,捕获,DOM事件流
  • 事件处理程序:HTML(内联),DOM0,DOM2,IE,兼容
  • 跨浏览器:添加和移除事件处理程序,获取事件对象,取消默认行为,取消冒泡
  • 自定义事件:Event,customEvent

17.1 事件流

HTML 中与 javascript 交互是通过事件驱动来实现的。事件流描述的是页面接收事件的顺序

第四代Web浏览器:IE事件流和Netscape事件流完全相反

  • IE:事件冒泡流

  • Netscape:事件捕获流

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>

事件冒泡

具体元素开始触发,从目标元素逐级向上传播

click事件的发生顺序:<div> -> <body> -> <html> -> document

所有现代浏览器都支持,但是实现方式有区别

  • IE5.5即以前会跳过<html>,直接<body> -> document
  • 现代浏览器会一直冒泡到window对象

事件捕获

不具体的元素最先收到事件,目的是想在目标元素接收到事件之前拦截事件

从document逐级向下传播到目标元素

click事件的发生顺序:document -> <html> -> <body> -> <div>

旧版本浏览器不支持,现实基本不用

DOM事件流

DOM2 Events规范规定,事件流分三个阶段:事件捕获、到达目标、事件冒泡

  • 事件捕获:用来提前拦截事件
  • 到达目标:目标元素接收事件
  • 事件冒泡:最迟在这一阶段响应事件

所有现代浏览器都支持,只有IE8及以前不支持

17.2 事件处理程序

事件处理程序的名字以”on”开头, 例如click事件的处理程序叫作onclick

HTML事件处理程序

HTML中的书写方式

1
2
3
4
5
6
7
<script>
function showMessage() {
console.log("this.value");
}
</script>
<input type="button" value="Click Me"
onclick="showMessage(this.value)"/>

HTML元素中的this指针指向事件的目标元素

注意,showMessage函数中的this指向全局变量

DOM0事件处理程序

把一个函数赋值给 (DOM元素的)一个事件处理程序属性

脚本中的书写方式

1
2
3
4
5
let btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log("this.id");
};
btn.onclick = null; // 移除事件处理程序

函数中的this指针指向事件的目标元素

DOM2事件处理程序

使用addEventListener()和removeEventListener()。

这两个方法暴露在 所有DOM节点上,它们接收3个参数:

  • 事件名,注意是事件名!没有on!!!
  • 事件处理函数,如果函数在其他地方定义,传函数名不要括号!!!!
  • 一个布尔值,
    • true表示在捕获阶段调用事件处理程序,
    • false(默认值)表示 在冒泡阶段调用事件处理程序。

可以为一个事件添加多个事件处理函数,会按添加顺序执行

1
2
3
4
5
6
function show(){
console.log(this.id)
}
let btn=document.getElementById("btn")
btnDOM2.addEventListener("click",show)
btnDOM2.removeEventListener("click",show)

如果addEventListener()添加的是匿名函数,那么removeEventListener()无法删除

事件处理程序一般添加到冒泡阶段,因为这样跨浏览器兼容好,捕获阶段一般用来拦截事件,没有拦截需求就不要置true!

IE事件处理程序

attachEvent()和detachEvent(),只在IE浏览器生效,IE11也不支持

接收两个同样的参数:事件处理程序的名字(有on)和事件处理函数,只会添加到冒泡阶段,因为IE8及以前只支持冒泡

1
2
3
4
5
6
function showThis() {
console.log(this === window); // true
}
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", showThis);
btn.detachEvent("onclick", showThis)

使用attachEvent()时,事件处理程序在全局作用域中运行,this指向window

跟DOM2一样也可以添加很多事件处理程序,但是触发顺序相反,是添加顺序的逆序

跟DOM2一样也不能删除匿名函数

跨浏览器事件处理程序

p777

检测浏览器对事件处理程序的支持,并分类实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var EventUtil = {
// 添加事件处理程序
addHandler: function(element, type, handler) {
if (element.addEventListener) { // DOM2
element.addEventListener(type, handler, false);
} else if (element.attachEvent) { // IE
element.attachEvent("on" + type, handler);
} else { // DOM0
element["on" + type] = handler;
}
},
// 移除事件处理程序
removeHandler: function(element, type, handler) {
if (element.removeEventListener) { // DOM2
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) { // IE
element.detachEvent("on" + type, handler);
} else { // DOM0
element["on" + type] = null;
}
}
};

17.3 事件对象

DOM事件对象

event对象,是传给事件处理程序的唯一参数,用DOM0或DOM2指定事件处理程序时,都会传入这个event对象

一些常用属性和方法:

event.type 事件类型

event.target 事件目标(目标元素)

event.preventDefault() 取消事件的默认行为(例如drag)

IE事件对象

IE事件对象根据不同的事件处理程序访问

DOM0:event对象是window对象的一个属性,在事件处理函数里let event=window.event,然后就可以用event.type之类的

IE:用attachEvent指定事件处理程序,event就是唯一的参数传给事件处理函数,同时它依然是window的属性,只是图方便所以传参了

HTML:直接在HTML里指定事件处理程序,可以通过event访问,因为HTML里event是一个自动生成的局部变量

跨浏览器事件对象

p786

兼容性跨浏览器获取event对象,目标元素之类的

  • event对象
  • 目标元素
  • 取消默认行为
  • 取消后续事件
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
var EventUtil = {
// 获取event对象
getEvent: function(event) {
return event ? event : window.event;
},
// 获取目标元素
getTarget: function(event) {
return event.target || event.srcElement;
},
// 取消事件默认行为
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
// 取消后续事件捕获和事件冒泡
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true; // 只取消冒泡
}
}
}

总结

事件流

冒泡和捕获

事件流是页面接受事件的顺序

事件冒泡流:IE浏览器提出,从目标元素逐级向上传播到document(现代浏览器会到window)

事件捕获流:NetScape提出,从document逐级向下传播到具体元素,目的是在目标元素接收到事件之前拦截事件,很多浏览器不支持所以一般不用

DOM事件流

DOM2 Events规范规定,事件流分三个阶段:事件捕获、到达目标、事件冒泡

  • 事件捕获:用来提前拦截事件
  • 到达目标:目标元素接收事件
  • 事件冒泡:最迟在这一阶段响应事件

所有现代浏览器都支持,只有IE8及以前不支持

事件处理程序

事件 click

事件处理程序 onclick

事件处理函数 handleClick()

DOM0 DOM2 *

参考

事件处理程序有哪几种指定方式:HTML、DOM0、DOM2、IE

  • HTML:直接在HTML中绑定,onclick="fun()"
    • 标签内的this指向目标元素,函数内的this指向window
  • DOM0element.onclick=...
    • 函数内的this指向目标元素
  • DOM2addEventListener() removeEventListener()
    • 函数内的this指向目标元素
    • 无on
  • IE:attachEvent() detachEvent()
    • 函数内的this指向window
    • 有on

addEventListener()参数

事件名、事件处理函数、布尔值(决定将事件处理函数添加到哪个阶段)

  • 事件名,注意是事件名!没有on!!!
  • 事件处理函数,如果函数在其他地方定义,传函数名不要括号!!!!
  • 一个布尔值,
    • true表示在捕获阶段调用事件处理程序,
    • false(默认值)表示 在冒泡阶段调用事件处理程序。

可以为一个事件添加多个事件处理函数,会按添加顺序执行

addEventListener()和attachEvent()不同

不同点 addEventListener() attachEvent()
事件处理程序指定方式 DOM2 IE
传入第一个参数 事件名无on 事件处理程序名有on
传入第三个参数
事件流阶段 可以指定添加到捕获或冒泡 只能添加到冒泡
浏览器支持 现代浏览器都支持 只有IE8及以前支持
事件处理函数的this指向 目标元素 window
绑定多个处理函数时的执行顺序 顺序 逆序

冒泡相关

什么事件不会触发冒泡

https://blog.csdn.net/Piconjo/article/details/104729923

前面加on也可以

UI事件:load unload abort error

焦点事件(Focus):blur focus

鼠标事件(Mouse):mouseenter mouseleave

Html5媒体事件(media):play mute

跨浏览器 *

取消冒泡:

DOM0、DOM2中传给事件处理函数的唯一默认参数是event:调用event.stopPropagation(),可以取消捕获和冒泡

IE中有点不一样:event.cancelBubble = true,只能取消冒泡

取消默认行为:

DOM:event.preventDefault()

IE:event.returnValue = false

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
var EventUtil = {
// 添加事件处理程序
addHandler: function(element, type, handler) {
if (element.addEventListener) { // DOM2
element.addEventListener(type, handler, false);
} else if (element.attachEvent) { // IE
element.attachEvent("on" + type, handler);
} else { // DOM0
element["on" + type] = handler;
}
},
// 移除事件处理程序
removeHandler: function(element, type, handler) {
if (element.removeEventListener) { // DOM2
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) { // IE
element.detachEvent("on" + type, handler);
} else { // DOM0
element["on" + type] = null;
}
},
// 获取event对象
getEvent: function(event) {
return event ? event : window.event;
},
// 获取目标元素
getTarget: function(event) {
return event.target || event.srcElement;
},
// 取消事件默认行为
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
// 取消后续事件捕获和事件冒泡
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true; // 只取消冒泡
}
}
};

自定义事件 *

参考

创建事件:3种方法

  • Event()构造函数,不能传数据
  • customEvent()构造函数,可以传数据
  • document.createEvent(),已废弃

触发事件:dispatchEvent(myEvent)

方法1:Event()构造函数

构造函数传入事件名称,可选配置项

  • bubbles:是否冒泡
  • cancelable:是否被取消
1
2
3
4
5
6
7
8
// Event创建事件
let myEvent1=new Event("myevent1",{"bubbles": true,"cancelable": true})
// 事件监听
document.addEventListener("myevent1",function(){
console.log("用Event()构造函数创建事件")
})
// 事件触发
document.dispatchEvent(myEvent1)

方法2:customEvent()构造函数

构造函数传入事件名称,可选配置项

  • detail:事件种要被传递的数据
  • bubbles:是否冒泡
  • cancelable:是否被取消
1
2
3
4
5
6
7
8
9
10
11
12
// CustomEvent创建事件
let myEvent2=new CustomEvent("myevent2",{
"detail": {"name": "用CustomEvent()构造函数创建事件"},
"bubbles": true,
"cancelable": true
})
// 事件监听
document.addEventListener("myevent2",function(event){
console.log(event.detail.name)
})
// 触发事件
document.dispatchEvent(myEvent2)
------ 本文结束 ❤ 感谢你的阅读 ------
------ 版权信息 ------

本文标题:红宝书学习:第十七章 事件

文章作者:Lury

发布时间:2022年02月28日 - 21:39

最后更新:2022年04月14日 - 22:01

原始链接:https://luryzhu.github.io/2022/02/28/JavaScript/prof_ch17/

许可协议:署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。