curTain

本文主要介绍 DOM 事件级别、DOM 事件模型、事件流、Event 对象常见的应用和自定义 DOM 事件。

1. DOM 事件级别

DOM 事件分为3个级别:DOM 0级事件处理,DOM 2级事件处理和DOM 3级事件处理。

1.1 DOM 0级事件

el.onclick=function(){}

DOM 0级事件
1
2
3
4
var btn = document.getElementById('btn');
btn.onclick = function(){
alert(this.innerHTML);
}

为元素的一种事件绑定一个方法,这些方法都在冒泡阶段执行。

1.2 DOM 2级事件

el.addEventListener(event-name, callback, useCapture)

  • event-name: 事件名称,可以是标准的DOM事件
  • callback: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event
  • useCapture: 默认是false,代表事件句柄在冒泡阶段执行
DOM 2级事件
1
2
3
4
5
6
7
8
9
var btn = document.getElementById('btn');
btn.addEventListener("click", test, false);
function test(e){
e = e || window.event;
alert((e.target || e.srcElement).innerHTML);
btn.removeEventListener("click", test)
}
//IE9-:attachEvent()与detachEvent()。
//IE9+/chrom/FF:addEventListener()和removeEventListener()

IE9以下的IE浏览器不支持 addEventListener()和removeEventListener(),使用 attachEvent()与detachEvent() 代替,因为IE9以下是不支持事件捕获的,所以也没有第三个参数,第一个事件名称前要加on。

1.3 DOM 3级事件

在DOM 2级事件的基础上添加了更多的事件类型。

  • UI事件,当用户与页面上的元素交互时触发,如:load、scroll
  • 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
  • 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dblclick、mouseup
  • 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
  • 文本事件,当在文档中输入文本时触发,如:textInput
  • 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
  • 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart
  • 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified
  • 动画事件,当css3 animation动画执行开始和结束时触发,如:webkitAnimationEnd mozAnimationEnd
  • 同时DOM3级事件也允许使用者自定义一些事件。

说明:

动画事件中不同浏览器的AnimationEnd写法:

  • 谷歌浏览器:webkitAnimationEnd
  • 火狐浏览器:mozAnimationEnd
  • IE系浏览器:MSAnimationEnd
  • 欧朋浏览器:oanimationend
  • 通用浏览器:animationend

2、DOM事件模型和事件流

DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。

(1)捕获阶段:事件从window对象自上而下向目标节点传播的阶段;
(2)目标阶段:真正的目标节点正在处理事件的阶段;
(3)冒泡阶段:事件从目标节点自下而上向window对象传播的阶段。

DOM事件捕获的具体流程

捕获是从上到下,事件先从window对象,然后再到document(对象),然后是html标签(通过document.documentElement获取html标签),然后是body标签(通过document.body获取body标签),然后按照普通的html结构一层一层往下传,最后到达目标元素。

这一系列的事件,就构成了事件流..

3、Event对象常见的应用

3.1 阻止默认事件

event. preventDefault()

调用此方法,将阻止默认事件的触发,例如:a 标签的跳转

阻止默认事件触发的方法:

阻止默认事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 1. 使用空的 js 
<a href="javascript:;">链接</a>

// 2. 返回 false
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick = function(e){
e = e || window.event;
return false;
}
</script>

// 3. 使用 preventDefault
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick = function(e){
e = e || window.event;
e.preventDefault();
}
</script>

3.2 阻止事件冒泡

event.stopPropagation()

调用此方法,事件将停止冒泡。

3.3 停止事件传播

event.stopImmediatePropagation()

调用此方法,将阻止此方法后面的方法执行。例如:一个事件绑定多个方法,方法依次调用,调用此方法后面的方法将不会执行,且阻止事件冒泡。

停止事件传播 stopImmediatePropagation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var btn = document.querySelector(".btn")
// 第一个事件
btn.addEventListener("click", function( e ){
console.log( "我是第一个注册的事件" )
})
// 注册第二个事件
btn.addEventListener("click", function( e ){
console.log( "我是第二个注册的事件,我要调用 event.stopImmediatePropagation()方法" )
e.stopImmediatePropagation()
})
// 注册第三个事件
btn.addEventListener("click", function( e ){
console.log( "我是第三个注册的事件" )
})
// document 捕获阶段事件
document.addEventListener( "click", function(){
console.log( "document---我在捕获阶段执行" )
}, true )
// document 冒泡阶段事件
document.addEventListener( "click", function(){
console.log( "document---我在冒泡阶段执行" )
})

运行结果

3.4 获取被点击的子元素

event.target

将被点击的子元素绑定在此属性上,我们可以用此 event.target + data-** 自定义属性 实现事件代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul>
<li data-index="1" >1</li>
<li data-index="2" >2</li>
<li data-index="3" >3</li>
<li data-index="4" >4</li>
<li data-index="5" >5</li>
</ul>
<script>
var ul = document.querySelector("ul")
ul.addEventListener( "click", function(e){
console.log( "e.target:" )
console.dir( e.target )
// 使用 dataset 获取绑定在元素上的标记属性(例如:元素下标)
console.log( "e.target.dataset", e.target.dataset )
})
</script>

运行结果:

3.5 获取当前注册事件元素

event.currentTarget

使用该属性,获取当前注册事件的元素。

4. 自定义事件

可以使用两种方式自定义事件:new Event( eventType )new CustomEvent( eventType, params )

4.1 new Event()

语法:event = new Event(eventType, eventInit);

一般只传递第一个参数``eventType`,后面为 Event 对象上的参数

4.2 CustomEvent()

语法:event = new CustomEvent(eventType, { detail:params });

eventType:事件名称
params:自定义参数

4.3 合并案例

自定义事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var btn = document.querySelector(".btn")
// Event 自定义事件
var eve = new Event("go")
btn.addEventListener( "go", function( e ){
console.log( "我是自定义事件:", e )
})
// CustomEvent 事件构造函数
function createCustomEvent( eventType = "mock-event", params = {} ){
return new CustomEvent( eventType, { detail: params } )
}
// CustomEvent 事件
var event = createCustomEvent( "customGo", { name: "tan" } )
btn.addEventListener( "customGo", function( data ){
console.log( "我是传参事件------", data )
})
// 触发事件各个
btn.addEventListener( "click", function(){
console.log( "我的定义的 Click 事件" )
btn.dispatchEvent( eve )
btn.dispatchEvent( event )
})

运行结果:

5. 总结

关于事件,需要记住

  1. addEventListener() 函数的使用,
  2. e.preventDefault() 禁止默认事件
  3. e.stopPropagation() 阻止冒泡
  4. e.target.dataset 获取 dom 中 data-** 自定义属性

自定义时间需要了解,并且自定义事件类似观察者模式,需要手动触发事件。

6. 参考材料

浪里行舟-DOM事件机制

DOM 事件详解

css3判断animation动画是否完成,以及在动画完成后执行事件

CSS浏览器前缀兼容写法

自定义事件——Event和CustomEvent

MDN-CustomEvent


 评论