1.事件:是用户或浏览器自身执行的某种动作,诸如click
、mouseover
、load
(这些都是事件的名字),而响应某个事件的函数就叫事件处理程序(事件监听器)。
2.事件流:描述从页面中接收事件的顺序。
具体分两种:
2-1.事件冒泡:事件开始时由最具体的元素(dom中嵌套层次最深的那个节点)接收,然后逐级向上传播到具体程度渐小的节点(文档)。
2-2.事件捕获:不太具体的节点(dom中嵌套层次浅)更早接收到事件,而最具体的节点最后接收到事件。(可在事件到达预定目标之前捕获它)
事件捕获
2-3.DOM事件流:分3个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段(DOM2规定)。首先发生的是事件捕获,为截获事件提供机会;然后是实际的目标接收到事件;最后是冒泡阶段,可对事件做出响应。
例如单击页面中div元素,事件流如图所示。
DOM2事件流
3.指定事件处理程序的方式:
3-1. HTML事件处理程序(*不建议使用这种方式
*)
<button onclick="alert(event.type)"></button>
<button onclick="showMsg"></button>
问题:
(1)HTML与JS代码紧密耦合,而且内容与行为不分离;
(2)时差问题,用户可能在HTML元素一出现在页面上就触发相关事件,但此时事件处理程序可能尚未具备执行条件。(如上段代码第2行,当按钮元素出现在页面上时,函数showMsg可能尚未定义);
3-2. DOM0级事件处理程序
事件处理程序(onclick)被当作元素(btn)的属性,被赋予一个函数,所以该函数中this
指向的就是该元素。
const btn=document.getElementById('btn');
btn.onclick=function () {
console.log(this.id); // btn
alert('btn clicked.');
}
删除指定的事件处理程序很简单,如下
btn.onclick=null;// 删除事件处理程序
注意:以此种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
3-3.DOM2级事件处理程序
addEventListener与removeEventListener分别用于指定和删除事件处理程序。
所有 DOM 节点都包含这两个方法,它们都接受3个参数:要处理的事件名;作为事件处理程序的函数、一个布尔值(若为 true,表示在捕获阶段调用事件处理程序;若为 false,表示在冒泡阶段调用事件处理程序)。
此种方式主要优点在于可以为同一元素的同一事件设置多个事件处理程序(如下段代码所示),并且可以指定在哪个阶段调用事件处理程序(捕获或冒泡)。
const btn=document.getElementById("btn");
btn.addEventListener("click", function (event) {
alert('btn clicked.');
},false);
btn.addEventListener("click", function (event) {
alert('btn clicked-2.');
},false);
注意:通过addEventListener
添加的事件处理程序只能通过removeEventListener
来移除,并且参数要一致。(主要是第二个参数———作为事件处理程序的函数,移除与添加时的这个参数必须是指向同一个函数对象,所以如果addEventListener添加的是匿名函数,那么将无法移除)。
4.事件对象:
在触发DOM上的某个事件时,会产生一个事件对象event
,它包含着所有与事件相关的信息,包括导致事件的元素、事件的类型、其他与特定事件相关的信息。
4-1.event
对象会被自动传入到事件处理程序中,在事件处理程序内部,对象this
始终指向currentTarget
,而target
则对应事件发生的真正目标元素。如下段代码所示,事件处理程序存在于按钮('btn')的父节点中(document.body),当在页面上点击该按钮时,由于按钮上并未设置相应的事件处理程序,click 事件就冒泡到了上层的 document.body(假设body中只有一个btn元素),在这里事件才得到处理。
document.body.onclick=function (event) {
alert(event.currentTarget===document.body);// true
alert(this===document.body);// true
alert(event.target===document.getElementById('btn'));//true
}
4-2. 若要阻止特定事件的默认行为,可以使用 preventDefault
方法(仅cancelable
属性为 true 的事件才行)。例如,链接默认的点击行为就是跳转到其href
指定的URL,如果想点击链接不跳转,而是弹窗显示URL,可如下设置:
const link=document.getElementById('myLink');
link.onclick=function (event) {
if(event.target.tagName==='A'){
event.preventDefault();
alert(event.target.getAttribute('href'));
}
}
4-3.区分stopPropagation
和stopImmediatePropagation
stopPropagation
:取消事件的进一步捕获或冒泡。
下例中,页面 body 中仅包含一个 button 元素。在页面上点击按钮,会弹出“btn clicked.”和“another response to the btn click event.”。因为在按钮的点击事件处理程序中,取消了点击事件的冒泡,所以在body元素上不会监听到此次点击事件。不过stopPropagation
并不影响在"btn"元素上设置的其他点击事件处理程序。
const btn=document.getElementById("btn");
btn.addEventListener("click", function (event) {
alert('btn clicked.');
event.stopPropagation();
},false);
btn.addEventListener("click", function (event) {
alert('another response to the btn click event.');
},false);
document.body.addEventListener("click", function (event) {
alert('body clicked.');
},false);
stopImmediatePropagation
:取消事件的或冒泡,同时阻止任何相关事件处理程序被调用。
下例中,点击按钮,只弹出“btn clicked”,说明stopImmediatePropagation
将按钮上的click事件的影响彻底终结。
const btn=document.getElementById("btn");
btn.addEventListener("click", function (event) {
alert('btn clicked.');
event.stopImmediatePropagation();
},false);
btn.addEventListener("click", function (event) {
alert('another response to the btn click event.');
},false);
document.body.addEventListener("click", function (event) {
alert('body clicked.');
},false);
网友评论