事件监听
【事件监听】
DOM 允许我们书写 JavaScript 代码以让 HTML 元素作出反应。
什么是 “事件”:用户与网页的交互动作。
什么是事件监听
“监听” 顾名思义,就是让计算机随时能够发现这个事件发生了,从而执行程序员预先编写好的一些程序。
设置事件监听的方法主要有 onxxx
和 addEventListener()
两种,二者的区别将在 “事件传播” 一课中介绍。
原始的事件处理方法:“直接通过事件绑定函数”
比如:
HTML:
<button onclick="add();">点击</button>
JS:
function add() { alert("相加"); }
以上方式不推荐使用!!!
事件模型
监听函数
浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。
JavaScript 有三种方法,可以为事件绑定监听函数。
HTML 的 on- 属性
HTML 语言允许在元素的属性中,直接定义某些事件的监听代码。
1 | <body onload="doSomething()"> |
上面代码为body
节点的load
事件、div
节点的click
事件,指定了监听代码。一旦事件发生,就会执行这段代码。
元素的事件监听属性,都是on
加上事件名,比如onload
就是on + load
,表示load
事件的监听代码。
注意,这些属性的值是将会执行的代码,而不是一个函数。
1 | <!-- 正确 --> |
一旦指定的事件发生,on-
属性的值是原样传入 JavaScript 引擎执行。因此如果要执行函数,不要忘记加上一对圆括号。
使用这个方法指定的监听代码,只会在冒泡阶段触发。
1 | <div onclick="console.log(2)"> |
上面代码中,<button>
是<div>
的子元素。<button>
的click
事件,也会触发<div>
的click
事件。由于on-
属性的监听代码,只在冒泡阶段触发,所以点击结果是先输出1
,再输出2
,即事件从子元素开始冒泡到父元素。
直接设置on-
属性,与通过元素节点的setAttribute
方法设置on-
属性,效果是一样的。
1 | el.setAttribute('onclick', 'doSomething()'); |
元素节点的事件属性
元素节点对象的事件属性,同样可以指定监听函数。
1 | window.onload = doSomething; |
使用这个方法指定的监听函数,也是只会在冒泡阶段触发。
注意,这种方法与 HTML 的on-
属性的差异是,它的值是函数名(doSomething
),而不像后者,必须给出完整的监听代码(doSomething()
)。
EventTarget.addEventListener()
所有 DOM 节点实例都有addEventListener
方法,用来为该节点定义事件的监听函数。
1 | window.addEventListener('load', doSomething, false); |
addEventListener
方法的详细介绍,参见下一个大标题。
小结
上面三种方法,第一种“HTML 的 on- 属性”,违反了 HTML 与 JavaScript 代码相分离的原则,将两者写在一起,不利于代码分工,因此不推荐使用。
第二种“元素节点的事件属性”的缺点在于,同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick
属性,后一次定义会覆盖前一次。因此,也不推荐使用。
第三种EventTarget.addEventListener
是推荐的指定监听函数的方法。它有如下优点:
- 同一个事件可以添加多个监听函数。
- 能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数。
- 除了 DOM 节点,其他对象(比如
window
、XMLHttpRequest
等)也有这个接口,它等于是整个 JavaScript 统一的监听函数接口。
this 的指向
监听函数内部的this
指向触发事件的那个元素节点。
1 | <button id="btn" onclick="console.log(this.id)">点击</button> |
执行上面代码,点击后会输出btn
。
其他两种监听函数的写法,this
的指向也是如此。
1 | // HTML 代码如下 |
上面两种写法,点击按钮以后也是输出btn
。
使用addEventListener方法添加监听
概述
DOM 节点的事件操作(监听和触发),都定义在EventTarget
接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象(比如,XMLHttpRequest
、AudioNode
、AudioContext
)也部署了这个接口。
该接口主要提供三个实例方法。
addEventListener()
:绑定事件的监听函数removeEventListener()
:移除事件的监听函数dispatchEvent()
:触发事件
EventTarget.addEventListener()
addEventListener
是 DOM 对象专门用来添加事件监听的方法,它的两个参数分别为【事件类型】和【事件回调】。
EventTarget.addEventListener()
用于在当前节点或对象上(即部署了 EventTarget 接口的对象),定义一个特定事件的监听函数。一旦这个事件发生,就会执行监听函数。该方法没有返回值。
1 | target.addEventListener(type, listener[, useCapture]); |
该方法接受三个参数。
type
:事件名称,大小写敏感。listener
:监听函数。事件发生时,会调用该监听函数。useCapture
:布尔值,如果设为true
,表示监听函数将在捕获阶段(capture)触发(后文事件的传播讲解)。该参数可选,默认值为false
(监听函数只在冒泡阶段被触发)。
下面是一个例子。
1 | function hello() { |
上面代码中,button
节点的addEventListener()
方法绑定click
事件的监听函数hello()
,该函数只在冒泡阶段触发。
关于参数,有两个地方需要注意。
首先,第二个参数除了监听函数,还可以是一个具有handleEvent
方法的对象,效果与监听函数一样。
1 | buttonElement.addEventListener('click', { |
上面代码中,addEventListener()
方法的第二个参数,就是一个具有handleEvent()
方法的对象。
完成事件监听分成3个步骤:
- 获取 DOM 元素
- 通过
addEventListener
方法为 DOM 节点添加事件监听 - 等待事件触发,如用户点击了某个按钮时便会触发
click
事件类型 - 事件触发后,相对应的回调函数会被执行
大白话描述:所谓的事件无非就是找个机会(事件触发)调用一个函数(回调函数)。
EventTarget.removeEventListener()
EventTarget.removeEventListener()
方法用来移除addEventListener()
方法添加的事件监听函数。该方法没有返回值。
1 | div.addEventListener('click', listener, false); |
removeEventListener()
方法的参数,与addEventListener()
方法完全一致。它的第一个参数“事件类型”,大小写敏感。
注意,removeEventListener()
方法移除的监听函数,必须是addEventListener()
方法添加的那个监听函数,而且必须在同一个元素节点,否则无效。
1 | div.addEventListener('click', function (e) {}, false); |
上面代码中,removeEventListener()
方法无效,因为监听函数不是同一个匿名函数。
1 | element.addEventListener('mousedown', handleMouseDown, true); |
上面代码中,removeEventListener()
方法也是无效的,因为第三个参数不一样。
EventTarget.dispatchEvent()
EventTarget.dispatchEvent()
方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault()
,则返回值为false
,否则为true
。
1 | target.dispatchEvent(event) |
dispatchEvent()
方法的参数是一个Event
对象的实例(详见《Event 对象》章节)。
1 | para.addEventListener('click', hello, false); |
上面代码在当前节点触发了click
事件。
如果dispatchEvent()
方法的参数为空,或者不是一个有效的事件对象,将报错。
下面代码根据dispatchEvent()
方法的返回值,判断事件是否被取消了。
1 | var canceled = !cb.dispatchEvent(event); |
常见的事件监听
常见的鼠标事件监听
事件名 | 事件描述 |
---|---|
onclick |
当鼠标单击某个对象 |
ondblclick |
当鼠标双击某个对象 |
onmousedown |
当某个鼠标按键在某个对象上被按下 |
onmouseup |
当某个鼠标按键在某个对象上被松开 |
onmousemove |
当某个鼠标按键在某个对象上被移动 |
onmouseenter |
当鼠标进入某个对象(相似事件 onmouseover ) |
onmouseleave |
当鼠标离开某个对象(相似事件 onmouseout ) |
常见的键盘事件监听
事件名 | 事件描述 |
---|---|
onkeypress |
当某个键盘的键被按下(系统按钮如箭头键和功能键无法得到识别) |
onkeydown |
当某个键盘的键被按下(系统按钮可以识别,并且会先于 onkeypress 发生) |
onkeyup |
当某个键盘的键被松开 |
常见的表单事件监听
事件名 | 事件描述 |
---|---|
onchange |
当用户改变完成域的内容 |
oninput |
当用户输入的时候 |
onfocus |
当某元素获得焦点(比如 tab 键或鼠标点击) |
onblur |
当某元素失去焦点 |
onsubmit |
当表单被提交 |
onreset |
当表单被重置 |
1 |
|
表单对象可以通过 “打点” name 属性,得到里面的子元素。
常见的页面事件监听
事件名 | 事件描述 |
---|---|
onload |
当页面或图像被完成加载 |
onunload |
当用户退出页面 |