跳至主要內容

22 【事件监听】

约 2565 字大约 9 分钟...

22 【事件监听】

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

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

1.什么是事件监听

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

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

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

比如:

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('触发事件')">

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

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

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

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

<!-- 错误 -->
<body onload="doSomething">

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

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

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

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

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

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

2.1.2 元素节点的事件属性

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

window.onload = doSomething;

div.onclick = function (event) {
  console.log('触发事件');
};

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

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

2.1.3 EventTarget.addEventListener()

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

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

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

2.1.4 小结

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

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

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

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

2.2 this 的指向

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

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

执行上面代码,点击后会输出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
);

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

3.使用addEventListener方法添加监听

3.1 概述

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

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

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

3.2 EventTarget.addEventListener()

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

image-20220825151249654
image-20220825151249654

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

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

该方法接受三个参数。

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

下面是一个例子。

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

var button = document.getElementById('btn');
button.addEventListener('click', hello, false);

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

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

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

buttonElement.addEventListener('click', {
  handleEvent: function (event) {
    console.log('click');
  }
});

上面代码中,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);

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

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

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

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

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

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

3.4 EventTarget.dispatchEvent()

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

target.dispatchEvent(event)

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

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

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

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

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

var canceled = !cb.dispatchEvent(event);
if (canceled) {
  console.log('事件取消');
} else {
  console.log('事件未取消');
}

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>

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

4.6 常见的页面事件监听

事件名事件描述
onload当页面或图像被完成加载
onunload当用户退出页面
已到达文章底部,欢迎留言、表情互动~
  • 赞一个
    0
    赞一个
  • 支持下
    0
    支持下
  • 有点酷
    0
    有点酷
  • 啥玩意
    0
    啥玩意
  • 看不懂
    0
    看不懂
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8