目录

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>
1
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采用了事件捕获的方式;

image

# 事件捕获和冒泡过程

如果所有的事件都监听,那么会按照如下顺序执行

捕获阶段:事件从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>
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

# 事件对象

当一个事件发生时,就会有和这个事件相关的很多信息;比如事件的类型是什么,你点击的是哪一个元素,点击的位置是哪里等等相关的信息;这些信息会被封装到一个Event对象中,这个对象由浏览器创建,称之为event对象;该对象给我们提供了想要的一些属性,以及可以通过该对象进行某些操作。

# 获取event对象

event对象会在传入的事件处理(event handler)函数回调时,被系统传入;可以在回调函数中拿到这个event对象。

spanEl.onclick = function(event){
    console.log(event)
}

spanEl.addEventListener('click', function(event){
    console.log(event)
})
1
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
})
1
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)
})

1
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>
1
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>
1
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

# 常见的鼠标事件

常见的鼠标事件(不仅仅是鼠标设备,也包括模拟鼠标的设备,比如手机、平板电脑)

image

# 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 常见的键盘事件

# 常见键盘事件

image

# 事件的执行顺序是 onkeydown、onkeypress、onkeyup

  • down事件先发生
  • press发生在文本被输入
  • up发生在文本输入完成

# 通过key和code来区分按下的键

  • code:“按键代码”("KeyA","ArrowLeft" 等),特定于键盘上按键的物理位置
  • key:字符("A","a" 等),对于非字符(non-character)的按键,通常具有与 code 相同的值。

# 常见的表单事件

image

oninput 输入内容的过程

onchange 内容确认发生改变

# 文档加载事件

  • DOMContentLoaded:浏览器已经完全加载HTML、并构建了DOM树,但像<img/>和样式表之类的外部资源可能尚未加载完成。
  • load:浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等
window.onload = function(){
    // 文档所有内容全部加载完成后执行
}

window.addEventListener('DOMContentLoaded', function(){
    // 文档中DOM加载完毕
})
1
2
3
4
5
6
7
上次更新: 2022/09/15, 08:23:57
最近更新
01
防抖和节流
02-06
02
正则表达式
01-29
03
async_await函数
12-30
更多文章>