JavaScript中事件监听
# 事件 Event
# 如何进行事件监听
- 在script中直接监听(很少使用)
- DOM属性,通过元素的on来监听事件
- 通过EventTarget中的addEventListener来监听
<div id="box" onclick="alert('click')">
box
</div>
<script>
box,ononclick = function(){
alert('click')
}
box.addEventListener('click', function(){
})
</script>
2
3
4
5
6
7
8
9
10
11
# 常见的事件列表
# 鼠标事件
- click 当鼠标点击一个元素时(触摸屏设备会在点击时生成)
- mouseover / mouseout —— 当鼠标指针移入/离开一个元素时
- mousedown / mouseup —— 当在元素上按下/释放鼠标按钮时
- mousemove —— 当鼠标移动时。
# 键盘事件
- keydown 和 keyup —— 当按下和松开一个按键时。
# 表单(form)事件
- submit —— 当访问者提交了一个
- focus —— 当访问者聚焦于一个元素时,例如聚焦于一个 。
# document事件
- DOMContentLoaded —— 当 HTML 的加载和处理均完成,DOM 被完全构建完成时。
# CSS 事件
- transitionend —— 当一个 CSS 动画完成时
# 事件流
事实上对于事件有一个概念叫做事件流,为什么会产生事件流呢?
当我们在浏览器上对着一个元素点击时,你点击的不仅仅是这个元素本身;因为我们的HTML元素是存在父子元素叠加层级的;比如一个span元素是放在div元素上的,div元素是放在body元素上的,body元素是放在html元素上的
# 事件冒泡和事件捕获
默认情况下事件是从最能层的元素向外依次传递的顺序,这个顺序称为事件冒泡(Event Bubble)。
还有另外一种监听事件流的方式就是从外层到内层(body -> span),这种称之为事件捕获(Event Capture)
产生两种处理流的原因
- IE采用了事件冒泡的方式,Netscape采用了事件捕获的方式;
# 事件捕获和冒泡过程
如果所有的事件都监听,那么会按照如下顺序执行
捕获阶段:事件从Window向下走进元素。
目标阶段:事件到达目标元素
冒泡阶段:事件从元素开始向上冒泡
实际上,可以通过event对象来获取当前的阶段 (eventPhase)
实际开发中经常使用的是事件冒泡\
<div class = "box">
<span></span>
</div>
<script>
var divEl = document.querySelector('.box')
var spanEl = document.querySelector('span')
// 冒泡过程
spanEl.addEventListener('click', function(){
console.log('span点击')
})
divEl.addEventListener('click', function(){
console.log('div冒泡点击')
})
body.addEventListener('click', function(){
console.log('body冒泡点击')
})
// 捕获过程, 传入第三个参数为true,表示监听捕获阶段事件
spanEl.addEventListener('click', function(){
console.log('span捕获')
}, true)
divEl.addEventListener('click', function(){
console.log('div捕获')
}, true)
body.addEventListener('click', function(){
console.log('body捕获')
}, true)
</script>
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
# 事件对象
当一个事件发生时,就会有和这个事件相关的很多信息;比如事件的类型是什么,你点击的是哪一个元素,点击的位置是哪里等等相关的信息;这些信息会被封装到一个Event对象中,这个对象由浏览器创建,称之为event对象;该对象给我们提供了想要的一些属性,以及可以通过该对象进行某些操作。
# 获取event对象
event对象会在传入的事件处理(event handler)函数回调时,被系统传入;可以在回调函数中拿到这个event对象。
spanEl.onclick = function(event){
console.log(event)
}
spanEl.addEventListener('click', function(event){
console.log(event)
})
2
3
4
5
6
7
# event常见的属性和方法
# 常见的属性
- type:事件类型
- target:当前事件发生的元素,哪个元素上发生事件,就指向谁
- currentTarget:当前处理事件的元素
- eventPhase:事件所处的阶段
- offsetX、offsetY:事件发生在元素内的位置
- clientX、clientY:事件发生在客户端内的位置
- pageX、pageY:事件发生在客户端相对于document的位置
- screenX、screenY:事件发生相对于屏幕的位置
# 常见的方法
- preventDefault:取消事件的默认行为
- stopPropagation:阻止事件的进一步传递(冒泡或者捕获都可以阻止)
# 事件处理函数中的this
在函数中可以使用this来获取当前的发生元素,因为在浏览器内部,调用‘event handler是绑定到当前的currentTarget
上的
boxEl.addEventListener('click', function(event){
console.log(this === event.target) // true
})
2
3
# EventTarget类
所有的元素,节点都继承自EventTarget
,事实上Window也继承自EventTarget
。EventTarget是一个DOM接口,主要用于添加、删除、派发Event事件。
# EventTarget常见的方法
- addEventListener:注册某个事件类型以及事件处理函数
- removeEventListener:移除某个事件类型以及事件处理函数
- dispatchevent:派发某个事件类型到
EventTarget
上
var boxEl = document.querySelector('.box')
boxEl.addEventListener('click', function(){
console.log('click')
})
boxEl.addEventListener('click', function(){
window.dispatchEvent(new Event('dispatchNewEvent'))
})
boxEl.addEventListener('dispatchNewEvent', function(event){
console.log('监听到派发事件dispatchNewEvent:', event)
})
2
3
4
5
6
7
8
9
10
11
12
13
# 事件委托 --- event delegation
事件冒泡在某种情况下可以帮助我们实现强大的事件处理模式 – 事件委托模式(也是一种设计模式)。
# 事件委托模式
当子元素被点击时,父元素可以通过冒泡可以监听到子元素的点击;并且可以通过event.target
获取到当前监听的元素;
# 案例:一个ul中存放多个li,点击某一个li会变成红色
方案一:监听每一个li的点击,并且做出响应
方案二:在ul中监听点击,并且通过event.target拿到对应的li进行处理,这种方案并不需要遍历后给每一个li上添加事件监听,所以它更加高效
<ul class=".list"></ul>
<script>
var listEl = document.querySelector('.list')
var currentActive = null
listEl.addEventListener('click', function(event){
if(currentActive) currentActive.classList.remove('active')
event.target.classList.add('active')
currentActive = event.target
})
</script>
2
3
4
5
6
7
8
9
10
# 事件委托的标记
某些事件委托可能需要对具体的子组件进行区分,这个时候我们可以使用data-*对其进行标记;比如多个按钮的点击,区分点击了哪一个按钮
<div class="btn-list">
<button data-action="new">新建</button>
<button data-action="search">搜索</button>
<button data-action="delete">删除</button>
</div>
<script>
var btnListEl = document.querySelector('.btn-list')
btnListEl.addEventListener('click', function(){
var action = event.target.dataset.action
switch(action) {
case 'new':
console.log('新建');
break;
case 'search':
console.log('搜索');
break;
case 'delete':
console.log('删除');
break;
default:
console.log('未知')
}
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 事件类型文档地址
https://developer.mozilla.org/zh-CN/docs/Web/Events
# 常见的鼠标事件
常见的鼠标事件(不仅仅是鼠标设备,也包括模拟鼠标的设备,比如手机、平板电脑)
# mouseover和mouseenter的区别
# mouseenter和mouseleave
- 不支持冒泡事件
- 进入子元素依然属于在该元素内,没有任何反应
# mouseover和mouseout
- 支持冒泡
- 进入元素的子元素时
- 先调用父元素的mouseout
- 再调用子元素的mouseover
- 因为支持冒泡,所以会将mouseover传递到父元素中
案例
<div class="box">
<button>删除</button>
<button>添加</button>
<button>修改</button>
</div>
<script>
let box = document.querySelector('.box')
box.onmouseover = function(event){
/* console.log(this)
console.log(box)
console.log(event);
console.log(this === box); */
if(event.target.tagName !== 'DIV'){
console.log(event.target.textContent)
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 常见的键盘事件
# 常见键盘事件
# 事件的执行顺序是 onkeydown、onkeypress、onkeyup
- down事件先发生
- press发生在文本被输入
- up发生在文本输入完成
# 通过key和code来区分按下的键
- code:“按键代码”("KeyA","ArrowLeft" 等),特定于键盘上按键的物理位置
- key:字符("A","a" 等),对于非字符(non-character)的按键,通常具有与 code 相同的值。
# 常见的表单事件
oninput 输入内容的过程
onchange 内容确认发生改变
# 文档加载事件
- DOMContentLoaded:浏览器已经完全加载HTML、并构建了DOM树,但像
<img/>
和样式表之类的外部资源可能尚未加载完成。 - load:浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等
window.onload = function(){
// 文档所有内容全部加载完成后执行
}
window.addEventListener('DOMContentLoaded', function(){
// 文档中DOM加载完毕
})
2
3
4
5
6
7