介绍

web页面的事件系统主要是为了对一系列动作的响应,比如:用户点击了一个按钮、用户关闭了网页等等。需要对这些动作做出处理,就需要我们注册一些事件处理程序。在web页面中我们称之为事件监听(EventListener)。

注意一下:web的事件并不是JavaScript语言的一部分,他们是被内置在浏览器中。

事件处理程序

事件就是用户或浏览器自身执行的某种动作。诸如click、load和mouseover,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以"on"开头,因此click事件的事件处理程序就是onclick,load事件的事件处理程序就是onload。为事件指定处理程序的方式有好几种。

内联属性

我们可以使用on加事件名称组成的内联属性来绑定事件,如onclick 、onmouseover等。

<button onclick="handler()">
  Button
</button>
function handler() {
  console.log('This is a button');
}

这样我们就可以在按钮点击的时候响应handler事件。

我们要注意一个问题,因为这样绑定的函数最后是在全局环境下执行的,所有函数内的this指向会是Window对象,如果我们想要获取具体是那个元素点击的,我们可以传递一个this过去。

<button onclick="handler(this, 333)">
  Button
</button>
function handlerWithParams(that, num) {
  console.log(that);
  console.log(num);
}

这样我们不仅可以获取到this,也可以随便传入参数,此处的this顺序也不会影响传值。

在内联事件处理程序中,一共有两个变量,除了this变量,还有一个event变量,代表事件对象

但是其实这样一种已经废弃了的写法,并不推荐使用。

这种写法的弊端显而易见,首先他是写在HTML内,不好维护。而且他并不支持批量绑定,假如我们有一千个元素,我们就需要这样写一千次,假如这个函数再发生什么改动,我们可能需要改所有用到这个函数的地方,维护成本巨大。

使用on绑定(DOM0级事件处理程序)

那真的有成百上千的元素需要绑定事件我们需要怎么做更好呢?

我们可以使用on加事件名的方式,讲JS文件和HTML文件分离。

单个绑定如下:

const btn = document.getElementById('btn');

btn.onclick = function() {
  console.log(1);
}

多个元素绑定;

const buttons = document.querySelectorAll('button');

buttons.forEach(function(button) {
  button.onclick = bgChange;
});

取消绑定

const buttons = document.querySelectorAll('button');

buttons.forEach(function(button) {
  button.onclick = bgChange;
});

// 取消
button.onclick = null;

虽然使用on的方式可以解决这个问题,但是不能绑定多个事件,后面绑定的事件会覆盖前面绑定的事件

btn.onclick = fn1
btn.onclick = fn2

上面的代码只有执行一个fn2

综上所述的两种方法,都有缺点,那么下面我们介绍DOM2中一种方法,可以解决这些问题,也是最推荐使用的。

addEventListener()和removeEventListener()(DOM2级事件处理程序)

最新的事件机制被定义在Document Object Model (DOM) Level 2 Events,他提供了一个新的函数addEventListener.

它接收三个参数:

  • type: string: 事件类型
  • listener: Function: 事件处理程序
  • useCapture: boolean = false: false代表在事件冒泡阶段执行,true代表在事件捕获阶段执行,一般我们都会把事件注册在冒泡阶段,如果不是特别需要,不建议把事件注册在捕获阶段。

看下面的例子:

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

function ev1() {
  console.log(`This is ${ev1.name}`)
}

function ev2() {
  console.log(`This is ${ev2.name}`)
}

btn.addEventListener('click', ev1) // ev1
btn.addEventListener('click', ev2) // ev2

执行上面的代码会发现两个函数都会被执行,这就解决了on方式不能绑定多个事件的问题,关于addEventLisener的问题,我们可以看详细的用法。

我们也可以使用removeEventListener来解除绑定,如下:

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

function ev1() {
  console.log(`This is ${ev1.name}`)
}

function ev2() {
  console.log(`This is ${ev2.name}`)
}

btn.addEventListener('click', ev1)
btn.addEventListener('click', ev2)

btn.removeEventListener('click', ev1);

上面的代码执行后,只会输出ev2的值,解除绑定需要事件类型一样,如:click,事件处理函数引用一样,匿名函数是无法解除的。

addEventListener是当前最推荐使用的。

参考