介绍
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
是当前最推荐使用的。
参考
- MDN, Introduction to events
- MDN, Events reference
- JavaScript高级程序设计第三版, 事件