吴志勇的博客 吴志勇的博客
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

吴志勇

......
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • HTML5&CSS3

  • CSS预处理语言

  • JavaScript

    • JavaScript

      • 01 【基础语法与基本数据类型】
      • 02 【JS表达式与操作符】
      • 03 【流程控制语句】
      • 04 【对象】
      • 05 【函数(上)】
      • 06 【函数(下)】
      • 07 【数组及常用方法】
      • 08 【标准库之Date对象】
      • 09 【标准库之Math对象和String对象】
      • 10 【标准库之RegExp对象】
      • 11 【标准库之JSON对象 JSON5】
      • 12 【语法之错误处理机制】
      • 13 【语法之编程风格】
      • 14 【语法之console 对象与控制台】
      • 15 【严格模式】
      • 16 【DOM概述】
      • 17 【Document 节点】
      • 18 【节点的关系和内部操作】
      • 19 【节点的增删改查】
      • 20 【节点的集合】
      • 21【节点的属性】
      • 22 【事件监听】
        • 1.什么是事件监听
        • 2.事件模型
          • 2.1 监听函数
          • 2.1.1 HTML 的 on- 属性
          • 2.1.2 元素节点的事件属性
          • 2.1.3 EventTarget.addEventListener()
          • 2.1.4 小结
          • 2.2 this 的指向
        • 3.使用addEventListener方法添加监听
          • 3.1 概述
          • 3.2 EventTarget.addEventListener()
          • 3.3 EventTarget.removeEventListener()
          • 3.4 EventTarget.dispatchEvent()
        • 4.常见的事件监听
          • 4.1 常见的鼠标事件监听
          • 4.2 常见的键盘事件监听
          • 4.3 常见的表单事件监听
          • 4.6 常见的页面事件监听
      • 23 【事件对象与鼠标事件】
      • 24 【键盘事件】
      • 25 【进度事件和表单事件】
      • 26 【触摸事件和其它常见事件】
      • 27 【三大家族scroll、offset、client】
      • 28 【事件传播】
      • 29【定时器和延时器】
      • 30【BOM和浏览器环境概述】
      • 31【window 对象】
      • 32 【Navigator 对象和Screen 对象】
      • 33 【History对象和Location对象】
      • 34 【表单和FormData 对象】
      • 35【Storage接口】
      • 36 【节流和防抖】
    • 01 【AJAX概述和基本使用】
    • jquery
    • ES6教程

  • nodejs

  • webpack

  • VUE

  • react

  • Typescript
  • 前端
  • JavaScript
  • JavaScript
wuzhiyong
2024-09-22

22 【事件监听】

# 22 【事件监听】

DOM 允许我们书写 JavaScript 代码以让 HTML 元素作出反应。

什么是 “事件”:用户与网页的交互动作。

# 1.什么是事件监听

“监听” 顾名思义,就是让计算机随时能够发现这个事件发生了,从而执行程序员预先编写好的一些程序。

设置事件监听的方法主要有 onxxx 和 addEventListener() 两种,二者的区别将在 “事件传播” 一课中介绍。

原始的事件处理方法:“直接通过事件绑定函数”

比如:

HTML:<button onclick="add();">点击</button>

JS:function add() { alert("相加"); }

以上方式不推荐使用!!!

# 2.事件模型

# 2.1 监听函数

浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。

JavaScript 有三种方法,可以为事件绑定监听函数。

# 2.1.1 HTML 的 on- 属性

HTML 语言允许在元素的属性中,直接定义某些事件的监听代码。

<body onload="doSomething()">
<div onclick="console.log('触发事件')">
1
2

上面代码为body节点的load事件、div节点的click事件,指定了监听代码。一旦事件发生,就会执行这段代码。

元素的事件监听属性,都是on加上事件名,比如onload就是on + load,表示load事件的监听代码。

注意,这些属性的值是将会执行的代码,而不是一个函数。

<!-- 正确 -->
<body onload="doSomething()">

<!-- 错误 -->
<body onload="doSomething">
1
2
3
4
5

一旦指定的事件发生,on-属性的值是原样传入 JavaScript 引擎执行。因此如果要执行函数,不要忘记加上一对圆括号。

使用这个方法指定的监听代码,只会在冒泡阶段触发。

<div onclick="console.log(2)">
  <button onclick="console.log(1)">点击</button>
</div>
1
2
3

上面代码中,<button>是<div>的子元素。<button>的click事件,也会触发<div>的click事件。由于on-属性的监听代码,只在冒泡阶段触发,所以点击结果是先输出1,再输出2,即事件从子元素开始冒泡到父元素。

直接设置on-属性,与通过元素节点的setAttribute方法设置on-属性,效果是一样的。

el.setAttribute('onclick', 'doSomething()');
// 等同于
// <Element onclick="doSomething()">
1
2
3

# 2.1.2 元素节点的事件属性

元素节点对象的事件属性,同样可以指定监听函数。

window.onload = doSomething;

div.onclick = function (event) {
  console.log('触发事件');
};
1
2
3
4
5

使用这个方法指定的监听函数,也是只会在冒泡阶段触发。

注意,这种方法与 HTML 的on-属性的差异是,它的值是函数名(doSomething),而不像后者,必须给出完整的监听代码(doSomething())。

# 2.1.3 EventTarget.addEventListener()

所有 DOM 节点实例都有addEventListener方法,用来为该节点定义事件的监听函数。

window.addEventListener('load', doSomething, false);
1

addEventListener方法的详细介绍,参见下一个大标题。

# 2.1.4 小结

上面三种方法,第一种“HTML 的 on- 属性”,违反了 HTML 与 JavaScript 代码相分离的原则,将两者写在一起,不利于代码分工,因此不推荐使用。

第二种“元素节点的事件属性”的缺点在于,同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。因此,也不推荐使用。

第三种EventTarget.addEventListener是推荐的指定监听函数的方法。它有如下优点:

  • 同一个事件可以添加多个监听函数。
  • 能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数。
  • 除了 DOM 节点,其他对象(比如window、XMLHttpRequest等)也有这个接口,它等于是整个 JavaScript 统一的监听函数接口。

# 2.2 this 的指向

监听函数内部的this指向触发事件的那个元素节点。

<button id="btn" onclick="console.log(this.id)">点击</button>
1

执行上面代码,点击后会输出btn。

其他两种监听函数的写法,this的指向也是如此。

// HTML 代码如下
// <button id="btn">点击</button>
var btn = document.getElementById('btn');

// 写法一
btn.onclick = function () {
  console.log(this.id);
};

// 写法二
btn.addEventListener(
  'click',
  function (e) {
    console.log(this.id);
  },
  false
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

上面两种写法,点击按钮以后也是输出btn。

# 3.使用addEventListener方法添加监听

# 3.1 概述

DOM 节点的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象(比如,XMLHttpRequest、AudioNode、AudioContext)也部署了这个接口。

该接口主要提供三个实例方法。

  • addEventListener():绑定事件的监听函数
  • removeEventListener():移除事件的监听函数
  • dispatchEvent():触发事件

# 3.2 EventTarget.addEventListener()

addEventListener 是 DOM 对象专门用来添加事件监听的方法,它的两个参数分别为【事件类型】和【事件回调】。

image-20220825151249654

EventTarget.addEventListener()用于在当前节点或对象上(即部署了 EventTarget 接口的对象),定义一个特定事件的监听函数。一旦这个事件发生,就会执行监听函数。该方法没有返回值。

target.addEventListener(type, listener[, useCapture]);
1

该方法接受三个参数。

  • type:事件名称,大小写敏感。
  • listener:监听函数。事件发生时,会调用该监听函数。
  • useCapture:布尔值,如果设为true,表示监听函数将在捕获阶段(capture)触发(后文事件的传播讲解)。该参数可选,默认值为false(监听函数只在冒泡阶段被触发)。

下面是一个例子。

function hello() {
  console.log('Hello world');
}

var button = document.getElementById('btn');
button.addEventListener('click', hello, false);
1
2
3
4
5
6

上面代码中,button节点的addEventListener()方法绑定click事件的监听函数hello(),该函数只在冒泡阶段触发。

关于参数,有两个地方需要注意。

首先,第二个参数除了监听函数,还可以是一个具有handleEvent方法的对象,效果与监听函数一样。

buttonElement.addEventListener('click', {
  handleEvent: function (event) {
    console.log('click');
  }
});
1
2
3
4
5

上面代码中,addEventListener()方法的第二个参数,就是一个具有handleEvent()方法的对象。

完成事件监听分成3个步骤:

  1. 获取 DOM 元素
  2. 通过 addEventListener 方法为 DOM 节点添加事件监听
  3. 等待事件触发,如用户点击了某个按钮时便会触发 click 事件类型
  4. 事件触发后,相对应的回调函数会被执行

大白话描述:所谓的事件无非就是找个机会(事件触发)调用一个函数(回调函数)。

# 3.3 EventTarget.removeEventListener()

EventTarget.removeEventListener()方法用来移除addEventListener()方法添加的事件监听函数。该方法没有返回值。

div.addEventListener('click', listener, false);
div.removeEventListener('click', listener, false);
1
2

removeEventListener()方法的参数,与addEventListener()方法完全一致。它的第一个参数“事件类型”,大小写敏感。

注意,removeEventListener()方法移除的监听函数,必须是addEventListener()方法添加的那个监听函数,而且必须在同一个元素节点,否则无效。

div.addEventListener('click', function (e) {}, false);
div.removeEventListener('click', function (e) {}, false);
1
2

上面代码中,removeEventListener()方法无效,因为监听函数不是同一个匿名函数。

element.addEventListener('mousedown', handleMouseDown, true);
element.removeEventListener("mousedown", handleMouseDown, false);
1
2

上面代码中,removeEventListener()方法也是无效的,因为第三个参数不一样。

# 3.4 EventTarget.dispatchEvent()

EventTarget.dispatchEvent()方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(),则返回值为false,否则为true。

target.dispatchEvent(event)
1

dispatchEvent()方法的参数是一个Event对象的实例(详见《Event 对象》章节)。

para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event);
1
2
3

上面代码在当前节点触发了click事件。

如果dispatchEvent()方法的参数为空,或者不是一个有效的事件对象,将报错。

下面代码根据dispatchEvent()方法的返回值,判断事件是否被取消了。

var canceled = !cb.dispatchEvent(event);
if (canceled) {
  console.log('事件取消');
} else {
  console.log('事件未取消');
}
1
2
3
4
5
6

# 4.常见的事件监听

# 4.1 常见的鼠标事件监听

事件名 事件描述
onclick 当鼠标单击某个对象
ondblclick 当鼠标双击某个对象
onmousedown 当某个鼠标按键在某个对象上被按下
onmouseup 当某个鼠标按键在某个对象上被松开
onmousemove 当某个鼠标按键在某个对象上被移动
onmouseenter 当鼠标进入某个对象(相似事件 onmouseover)
onmouseleave 当鼠标离开某个对象(相似事件 onmouseout)

# 4.2 常见的键盘事件监听

事件名 事件描述
onkeypress 当某个键盘的键被按下(系统按钮如箭头键和功能键无法得到识别)
onkeydown 当某个键盘的键被按下(系统按钮可以识别,并且会先于 onkeypress 发生)
onkeyup 当某个键盘的键被松开

# 4.3 常见的表单事件监听

事件名 事件描述
onchange 当用户改变完成域的内容
oninput 当用户输入的时候
onfocus 当某元素获得焦点(比如 tab 键或鼠标点击)
onblur 当某元素失去焦点
onsubmit 当表单被提交
onreset 当表单被重置
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form id="myform">
        <p>
            姓名:
            <input type="text" name="nameField">
        </p>
        <p>
            年龄:
            <input type="text" name="ageField">
        </p>
        <p>
            <input type="submit">
        </p>
    </form>

    <script>
        var myform = document.getElementById('myform');
        // 表单对象可以通过 “打点”name 属性,得到里面的子元素。
        var nameField = myform.nameField;
        var ageField = myform.ageField;

        nameField.onchange = function () {
            console.log('你已经修改完了姓名');
        };

        nameField.oninput = function () {
            console.log('你正在修改姓名');
        };

        nameField.onfocus = function () {
            console.log('姓名框已经得到了焦点');
        }

        nameField.onblur = function () {
            console.log('姓名框已经失去了焦点');
        }

        myform.onsubmit = function () {
            alert('你正在尝试提交表单');
         /* return true;  可以省略,默认执行表单提交 */
         /* return false; 不执行表单提交,比如用户信息填写不全就不应该提交表单 */
        }
    </script>
</body>

</html>
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

表单对象可以通过 “打点” name 属性,得到里面的子元素。

# 4.6 常见的页面事件监听

事件名 事件描述
onload 当页面或图像被完成加载
onunload 当用户退出页面
上次更新: 2024-09-30 01:09:25

← 21【节点的属性】 23 【事件对象与鼠标事件】→

Copyright © 2020-2025 wuzhiyong
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式