浏览器中的事件介绍

470 阅读5分钟

「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

基本概念

定义:事件是在编程时系统内发生的动作或者发生的事情——系统会在事件出现时产生或触发某种信号,并且会提供一个自动加载某种动作(列如:运行一些代码)的机制。

在 Web 中, 事件在浏览器窗口中被触发并且通常被绑定到窗口内部的特定部分 — 可能是一个元素、一系列元素、被加载到这个窗口的 HTML 代码或者是整个浏览器窗口。举几个可能发生的不同事件:

  • 用户在某个元素上点击鼠标或悬停光标。
  • 用户在键盘中按下某个按键。
  • 用户调整浏览器的大小或者关闭浏览器窗口。
  • 提交表单。
  • 播放、暂停、关闭视频。

每个可用的事件都会有一个事件处理器,也就是事件触发时会运行的代码块。当我们定义了一个用来回应事件被激发的代码块的时候,我们说我们注册了一个事件处理器。注意事件处理器有时候被叫做事件监听器

使用网页事件的方式

可以通过多种不同的方法将事件监听器代码添加到网页,以便在关联的事件被触发时运行它。

HTML属性(不建议使用)

行内事件处理器,处理程序可以设置在 HTML 中名为 on<event> 的特性(attribute)中。

例如:onclick="alert('Click!')"

<input value="Click me" onclick="alert('Click!')" type="button">

在鼠标点击时,onclick 中的代码就会运行。

注意,在 onclick 中,要使用单引号,因为特性本身使用的是双引号。如果忘记了代码是在特性中的,而使用了双引号,像这样:onclick="alert("Click!")",那么它将无法正确运行。

DOM属性

可以使用 DOM 属性(property)on<event> 来分配处理程序。

例如:elem.onclick

const btn = document.querySelector('button');

btn.onclick = function() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}

这个onclick是被用在这个情景下的事件处理器的属性,它就像 button 其他的属性(如btn.style),但是有一个特别的地方,当把一些代码赋值给它的时候,只要事件触发代码就会运行。

可以将一个有名字的函数赋值给事件处理参数

function sayThanks() {
  alert('Thanks!');
}

elem.onclick = sayThanks;

注意:函数不加括号,如果添加了括号,那么 sayThanks() 就变成了一个函数调用。

// 正确✔️
button.onclick = sayThanks;

// 错误❌
button.onclick = sayThanks();

扩展

如果同时用HTML属性和DOM属性添加事件,执行的是谁?

后面的事件会覆盖前面的。

<input type="button" id="elem" onclick="alert('Before')" value="Click me">
<script>
  elem.onclick = function() { // 覆盖了现有的处理程序
    alert('After'); // 只会显示此内容
  };
</script>

注意大小写问题!

  • html属性,大小写不敏感。ONCLICKonClick 以及 onCLICK 都一样可以运行。但是特性通常是小写的:onclick
  • DOM属性,大小写敏感,只能写elem.onclick,像这种elem.ONCLICK是不行的。

addEventListener

EventTarget.addEventListener() 方法是将指定的事件监听器注册到目标对象上,当该对象触发指定的事件时,指定的回调函数就会被执行。

添加监听事件

语法:element.addEventListener(event, listener[, options]);

event:事件名,例如:"click"。

listener:处理程序。

options:具有以下属性的附加可选对象:
	- once:如果为 true,那么会在被触发后自动删除监听器。
	- capture:事件处理的阶段(true 事件捕获  false 事件冒泡)。
	- passive:如果为 true,那么处理程序将不会调用 preventDefault()

移除监听事件

语法:element.removeEventListener(event, handler[, options]);

示例

/**部分代码**/
//添加
myElement.addEventListener('click', functionA);

//移除
myElement.removeEventListener('click', functionA);

关于第三个参数的使用之冒泡和捕获

elem.addEventListener(..., {capture: true}) 或者,用 {capture: true} 的别名 "true" elem.addEventListener(..., true)

//后面文章会细说这两个
myElement.addEventListener('click', functionA); //冒泡
myElement.addEventListener('click', functionA, true); //捕获

handleEvent

上面说到的addEventListener()中的listener:当指定的事件类型发生时被通知到的一个对象。

该参数必须是实现EventListener接口的一个对象或函数。即,第二个参数除了可以传入函数外,还可以传入对象。

interface EventListener {
  // 注意:该接口属于DOM2, 所以IE6~IE8不能直接使用
  void handleEvent(Event evt);
};

也就是说事件会自动在传入对象中寻找handleEvent方法。

所以你可以把所有事件都写到一个obj当中,根据事件类型区分,而不用为每个事件类型定义不同的处理函数。

示例:

var obj = {
    handleEvent: function(e) {
        switch(e.type) {
            case "click":
                 this.demoClick(event);
                break;
            case "mousedown":
                this.demoMousedown(event);
                break;
        }
    },
    demoClick:function(event){  console.log("点击事件");},
    demoMousedown:function(event){   console.log("按下鼠标"); },
};
 
document.body.addEventListener('click', obj, false);
document.body.addEventListener('mousedown', obj, false);

事件对象event

当事件发生时,浏览器会创建一个 event 对象,将详细信息放入其中,并将其作为参数传递给处理程序。

比如点击事件

<input type="button" value="Click me" id="elem">

<script>
  elem.onclick = function(event) {
      console.log(event);
  };
</script>

部分打印结果:

image-20211125003212262

event 对象的一些属性:

  • event.type :事件类型,这里是 "click"
  • event.currentTarget:处理事件的元素。这与 this 相同,除非处理程序是一个箭头函数,或者它的 this 被绑定到了其他东西上,之后我们就可以从 event.currentTarget 获取元素了。
  • event.clientX / event.clientY:指针事件(pointer event)的指针的窗口相对坐标。

参考资料:

Introduction to browser events

EventTarget.addEventListener

MDN EventListener


🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

👉 一起来看看JS的原型继承

👉 JS中的getter和setter你会用吗?

👉 深入理解ES6箭头对象

👉 JS的装饰器模式实例分析