通过使用 JavaScript,您可以在网页上发生事件时执行预先注册的处理。当事件发生时执行的过程或函数称为事件处理程序。当您在网页上单击鼠标或按下键盘键时,或者当您尝试查看的网页已完成加载时,可能会发生事件。在这里,我们将解释如何使用 JavaScript 处理事件,以及您可以针对每种类型的事件具体执行哪些操作。
目录
26-1 点击事件:点击鼠标时
26-2 dblclick 事件:鼠标双击时
26-3 将事件处理程序注册为 HTML 元素的属性
26-4 将事件处理程序注册到 DOM 中检索到的元素的属性
26-5 使用 addEventListener 方法注册一个事件监听器
26-6 关于注册事件处理器的代码写位置的注意事项和对策
26-7 获取有关已发生事件(Event)的信息
26-8 关于 Event.currentTarget 和 Event.target 的区别
26-9 事件传播(捕获和冒泡)
26-10 取消事件传播
26-11 取消事件的默认行为(preventDefault)
26-12 从代码中引发事件 (dispatchEvent)
点击事件的使用方法
click 事件是在鼠标光标悬停在某个元素上时按下鼠标然后松开时发生的事件。发生在 Element 对象上。
事件类型 : MouseEvent
冒泡可用性 : 可能
取消可能性 : 可能
使用 onclick 属性为元素属性值注册事件处理程序。
onclick 属性
<input type="button" value="button" onclick="buttonClick()">
<script>
function buttonClick(){
alert('Click');
}
</script>
使用 onclick 属性在使用 DOM 检索的元素的属性上注册事件处理程序。如果使用属性,也可以使用匿名函数或箭头函数表达式来编写它们。(有关更多信息,请参阅 使用匿名函数和箭头函数编写事件处理程序。)
onclick 属性
<input type="button" value="button" id="xxx">
<script>
function butotnClick(){
alert('Click');
}
let button = document.getElementById('xxx');
button.onclick = butotnClick;
</script>
使用 addEventListener 方法注册事件侦听器时,将“click”指定为第一个参数。如果使用 addEventListener 方法,也可以使用匿名函数或箭头函数表达式来编写。(有关详细信息,请参阅 使用 addEventListener 方法注册事件侦听器。)
addEventListener 方法
<input type="button" value="button" id="xxx">
<script>
function butotnClick(){
alert('Click');
}
let button = document.getElementById('xxx');
button.addEventListener('click', butotnClick);
</script>
当您使用元素的属性注册事件处理程序时,或者当您使用 addEventListener 方法注册事件侦听器时,当事件发生并调用事件处理程序或事件侦听器时,有关发生的事件的信息将作为argument. 你将被传递一个可以使用的 Event 对象。在单击事件的情况下,将传递继承自 Event 对象的 MouseEvent 对象。
<input type="button" value="button" id="xxx">
<script>
function butotnClick(event){
console.log(event);
}
let button = document.getElementById('xxx');
button.addEventListener('click', butotnClick);
</script>
您可以通过引用在事件处理程序或事件侦听器中传递的 MouseEvent 对象的属性来引用有关发生的事件的信息。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>请单击按钮</p>
<input type="button" value="button" id="btn">
<script>
function butotnClick(){
alert('Click');
}
let button = document.getElementById('btn');
button.addEventListener('click', butotnClick);
</script>
</body>
</html>
单击屏幕上显示的任何输入元素将显示警报。
click、mousedown 和 mouseup 事件发生的顺序
单击事件是在按下鼠标然后松开时触发的事件。类似的事件有 mousedown 事件,当按下鼠标时触发,mouseup 事件,当鼠标松开时触发。
如果您为同一元素上的三个事件注册事件侦听器,然后单击鼠标,则事件触发的顺序为 mousedown -> mouseup -> click 。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>请单击按钮</p>
<input type="button" value="button" id="btn">
<script>
let button = document.getElementById('btn');
button.addEventListener('click', function(){
console.log('Click');
});
button.addEventListener('mousedown', function(){
console.log('MouseDown');
});
button.addEventListener('mouseup', function(){
console.log('MouseUp');
});
</script>
</body>
</html>
input 元素为 click、mousedown 和 mouseup 事件注册了三个事件侦听器。单击屏幕上显示的输入元素会依次调用 mousedown 事件、mouseup 事件和 click 事件的事件侦听器。
获取连续点击鼠标的次数
单击间隔非常短的鼠标单击被视为双击或三次单击。要获取点击事件发生时的连续点击次数,请参考 UIEvent.detail 属性。
event.detail
※MouseEvent 继承自 UIEvent。
通过引用调用事件处理程序或事件侦听器时作为参数传递的 MouseEvent 对象的 detail 属性,您可以看到连续单击了多少次。
button.addEventListener('click', function(event){
let count = event.detail;
});
click事件本身是在每次点击时产生的,但是如果是短时间连续点击,detail属性的值会按顺序从1开始计数。当点击之间有间隔时,细节属性的值会自动重置。
示例代码
次のサンプルを見てください请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>请单击按钮。</p>
<input type="button" value="button" id="btn">
<script>
let button = document.getElementById('btn');
button.addEventListener('click', function(event){
let count = event.detail;
console.log('Click count is ' + count);
});
</script>
</body>
</html>
如果你连续点击屏幕上显示的输入元素,你连续点击的次数将输出到控制台。
当鼠标光标在元素上时在很短的时间内单击两次鼠标时会触发 dblclick 事件。您可以为 ondblclick 属性或 ondblclick 属性设置事件处理程序,或者通过将 dblclick 指定为 addEventListener 方法的参数来注册事件侦听器。在这里,我们将说明如何使用 JavaScript 编写发生 dblclick 事件时的处理。
如何使用 dblclick 事件
当鼠标光标在元素上时在很短的时间内单击两次鼠标时会触发 dblclick 事件。发生在 Element 对象上。
事件类型 : MouseEvent
冒泡可能性 : 可能
取消可能性 : 可能
使用 ondblclick 属性为元素属性值注册事件处理程序。
ondblclick 属性
<input type="button" value="button" ondblclick="buttonDoubleclick()">
<script>
function buttonDoubleclick(){
alert('Double Click');
}
</script>
使用 ondblclick 属性在使用 DOM 检索的元素的属性上注册事件处理程序。如果使用属性,也可以使用匿名函数或箭头函数表达式来编写它们。
ondblclick 属性
<input type="button" value="button" id="xxx">
<script>
function butotnDoubleclick(){
alert('Double Click');
}
let button = document.getElementById('xxx');
button.ondblclick = butotnDoubleclick;
</script>
使用 addEventListener 方法注册事件侦听器时,将“dblclick”指定为第一个参数。如果使用 addEventListener 方法,也可以使用匿名函数或箭头函数表达式来编写。
addEventListener 方法
<input type="button" value="button" id="xxx">
<script>
function butotnDoubleclick(){
alert('Double Click');
}
let button = document.getElementById('xxx');
button.addEventListener('dblclick', butotnDoubleclick);
</script>
当使用元素的属性注册事件处理程序时,或者当您使用 addEventListener 方法注册事件侦听器时,当事件发生并调用事件处理程序或事件侦听器时,有关发生的事件的信息将作为argument. 你将被传递一个可以使用的 Event 对象。在 dblclick 事件的情况下,将传递继承 Event 对象的 MouseEvent 对象。
<input type="button" value="button" id="xxx">
<script>
function butotnDoubleclick(event){
console.log(event);
}
let button = document.getElementById('xxx');
button.addEventListener('dblclick', butotnDoubleclick);
</script>
您可以通过引用在事件处理程序或事件侦听器中传递的 MouseEvent 对象的属性来引用有关发生的事件的信息。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<p>请单击按钮</p>
<input type="button" value="button" id="xxx">
<script>
function butotnDoubleclick(){
alert('Double Click');
}
let button = document.getElementById('xxx');
button.addEventListener('dblclick', butotnDoubleclick);
</script>
</body>
</html>
如果您在屏幕上可见的输入元素上双击,则会出现警告。
click 和 dblclick 事件之间的关系
click 和 dblclick 事件都是在单击鼠标时发生的事件。其他类似的事件是 mousedown 事件,当按下鼠标时触发,mouseup 事件,当释放鼠标时触发。
如果您为同一元素上的 click 和 dblclick 事件注册事件侦听器,然后快速单击鼠标,则 click 事件会在 dblclick 事件触发之前触发两次。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="btn">
<script>
let button = document.getElementById('btn');
button.addEventListener('click', function(){
console.log('Click');
});
button.addEventListener('dblclick', function(){
console.log('Double Click');
});
</script>
</body>
</html>
input 元素具有为 click 和 dblclick 事件注册的事件侦听器。如果你点击显示在屏幕上的input元素的时间间隔很短,dblclick事件的事件监听器会在click事件的事件监听器被调用两次后被调用。
注册事件处理程序有三种方法,但这里我们将说明如何将事件处理程序注册为 HTML 元素的属性。请注意,此方法在 HTML 代码中包含 JavaScript 代码,目前不推荐使用。使用 DOM 属性或使用事件侦听器。
将事件处理程序注册为 HTML 元素的属性
如何使用 HTML 元素的属性注册事件处理程序。例如,要注册一个当用鼠标单击输入元素时要执行的事件处理程序,请编写如下。
<input type="button" value="button" onclick="事件处理器">
将事件处理程序编写为 onclick 属性的值。将要执行的 JavaScript 代码或函数放在事件处理程序中。
直接编写JavaScript代码作为事件处理程序,写法如下。如果只有一条语句要执行,则结尾的分号可以省略。
<input type="button" value="button" onclick="console.log('Hello')">
你也可以写多个句子。不要忘记末尾的分号 (;),除了最后一条语句。
<input type="button" value="button" onclick="let d = new Date();console.log(d.toString())">
属性名称因事件类型而异。onclick 属性为 click 事件注册事件处理程序,onmousedown 属性为 mousedown 事件注册事件处理程序,依此类推 + 事件名称。有关正在发生的事件的信息,请参阅本页底部。
* 在 HTML 中,属性名称不区分大小写。因此,您可也以编写 onClick=”…” 或 ONCLICK=”…” 而不是 onclick=”…”。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" onclick="alert('Hello')">
</body>
</html>
单击显示的按钮以显示警报对话框。
在事件处理程序中调用函数
除了直接在事件处理程序中编写 JavaScript 代码外,您还可以调用单独定义的函数作为事件处理程序。
<script>
function butotnClick(){
console.log('Hello');
}
</script>
<input type="button" value="button" onclick="buttonClick()">
它调用单独定义为事件处理程序的 buttonClick 函数。
为 HTML 属性注册事件处理程序时,您只需调用外部定义的函数,而不是设置回调函数。因此,以“函数名()”的形式描述。您还可以在调用函数时指定任何参数。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<p>单击按钮。</p>
<script>
function buttonClick(){
let d = new Date();
console.log(d.toString());
}
</script>
<input type="button" value="button" onclick="buttonClick()">
</body>
</html>
单击显示的按钮可获取当前日期和时间并将其输出到控制台。
事件类型列表
将事件处理程序注册为 HTML 元素的属性时,需要编写与要编写处理的事件类型对应的属性的事件处理程序。有关可设置的事件类型和属性的列表,请参见下一页。
・8.1.7.2 Event handlers on elements, Document objects, and Window objects
提供了大量的事件处理程序属性。下面是对似乎最常用的内容的快速介绍。
属性值 | 事件类型 |
onclick | 当鼠标按钮在元素上单击时 |
oncontextmenu | 鼠标右键单击时 |
ondblclick | 当鼠标按钮在元素上双击时 |
onmousedown | 当鼠标在元素上按下时 |
onmouseup | 当鼠标按钮在元素上释放时 |
onmousemove | 当鼠标悬停在元素上时 |
onmouseover | 当鼠标移到侦听器所附加的元素或子元素上时 |
onmouseout | 当鼠标离开监听器所附加的元素或子元素时 |
onselect | 选择文本时 |
onwheel | 当鼠标滚轮旋转时 |
onauxclick | 在元素上单击非主鼠标按钮(例如中间按钮)时 |
onkeydown | 当按下任何键时 |
onkeyup | 当释放任何键时 |
onkeypress | 当任何键处于按下状态时 |
onblur | 元素失去焦点时(无冒泡) |
onfocus | 当元素获得焦点时(无冒泡) |
onchange | 当确认元素值更改时(<input>、<select>、<textarea>) |
oninput | 当元素值改变时(<input>, <select>, <textarea>) |
onsubmit | 当按下提交按钮时 |
onreset | 当按下重置按钮时 |
onload | 当整个页面加载了所有样式表、图像等时。 |
onabort | 加载因错误以外的原因中止时 |
onerror | 当加载失败并出现错误时 |
根据你要处理的事件类型,在相应的属性中注册事件处理器。
作为注册事件处理程序的方法,我们将说明如何为使用 DOM 获取的元素的属性注册事件处理程序。基本用法类似于如何为 HTML 元素的属性注册事件处理程序,但仅使用 JavaScript 代码即可实现。
在元素对象属性上注册事件处理程序
将事件处理程序设置为 HTML 元素的属性时,事件处理程序直接写在元素的属性值中。
<input type="button" value="button" onclick="事件处理器">
使用 DOM,您可以将 HTML 页面中的任何元素作为元素对象获取。然后为元素对象的属性设置事件处理程序。
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.property = 事件处理器;
</script>
用 HTML 代码编写的输入标签不再包含 JavaScript 代码,事件处理可以用 JavaScript 代码完成。
* 与 HTML 属性值不同,属性区分大小写。所以button.onclick=’…’不能写成button.onClick=’…’。
在事件处理程序中设置回调函数
如果将事件处理程序设置为 HTML 元素的属性,则编写了要执行的 JavaScript 代码,但如果将事件处理程序设置为属性,则设置了事件发生时将调用的回调函数。
例如,为一个id属性值为xxx的input标签注册点击事件的事件处理器,写法如下。
<input type="button" value="button" id="xxx">
<script>
function butotnClick(){
console.log('Hello');
}
let button = document.getElementById('xxx');
button.onclick = butotnClick;
</script>
回调函数的buttonClick函数是为点击事件设置的。(注意设置回调函数时,只写函数名)。当此元素上发生单击事件时,将调用 buttonClick 函数。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="mybutton">
<script>
function butotnClick(){
let d = new Date();
console.log(d.toString());
}
let button = document.getElementById('mybutton');
button.onclick = butotnClick;
</script>
</body>
</html>
单击显示的按钮可获取当前日期和时间并将其输出到控制台。
使用匿名函数和箭头函数编写事件处理程序
注册为事件处理程序的回调函数也可以使用匿名函数编写。
例如,使用匿名函数为id属性值为xxx的input标签注册点击事件的事件处理器,描述如下。
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.onclick = function(){
console.log('Hello');
};
</script>
同样,在使用箭头函数表达式时,写成如下。
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.onclick = () => {
console.log('Hello');
};
</script>
两种方法都产生基本相同的结果。(这不是特定于事件处理,而是匿名函数和箭头函数表达式在函数内部对this有不同的取值。)
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button1" id="mybutton1">
<input type="button" value="button2" id="mybutton2">
<script>
let button1 = document.getElementById('mybutton1');
button1.onclick = function(){
let num = Math.floor(Math.random() * 6) + 1;
console.log('骰子值为' + num + '。');
};
let button2 = document.getElementById('mybutton2');
button2.onclick = () => {
let num = Math.floor(Math.random() * 6) + 1;
console.log('骰子值为' + num + '。');
};
</script>
</body>
</html>
左边的按钮使用匿名函数,右边的按钮使用箭头函数表达式。单击任一按钮将获得 1 到 6 之间的随机值并将其打印到控制台。
释放事件处理程序
每个元素对象具有与事件类型数量一样多的属性,如果没有注册事件处理程序,则存储 null。
要删除已注册事件处理程序的属性的事件处理程序,请将 null 分配给该属性。例如,要取消注册在onclick属性中的事件处理器,写成如下。
button.onclick = null;
单击事件的事件处理程序现在已被删除。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="mybutton">
<script>
let button = document.getElementById('mybutton');
button.onclick = function(){
let d = new Date();
console.log(d.toString());
// 一旦调用释放事件处理程序
this.onclick = null;
};
</script>
</body>
</html>
单击显示的按钮可获取当前日期和时间并将其输出到控制台。
调用回调函数时接收事件信息
当将回调函数注册为事件处理程序时(这也适用于匿名函数和箭头函数表达式),当事件发生并调用回调函数时,包含有关发生的事件的信息的 Event 对象将作为参数传递。我会来。如果要在函数中使用事件的信息,请在回调函数中描述参数。
<script>
function butotnClick(event){
// ...
}
let button = document.getElementById('xxx');
button.onclick = butotnClick;
</script>
作为参数接收的 Event 对象中包含的信息因事件类型而异,但它包括诸如单击鼠标的位置和按下的键盘类型等信息。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="mybutton">
<script>
let button = document.getElementById('mybutton');
button.onclick = function(event){
console.log('event.type:' + event.type);
console.log('event.target:' + event.target);
};
</script>
</body>
</html>
单击显示的按钮时,有关发生的事件类型和事件发生的元素的信息将输出到控制台。
作为注册事件处理程序的方法,我们将说明如何使用从 DOM 获取的节点的 addEventListener 方法注册事件处理程序。使用addEventListener方法注册事件的函数,具体称为事件监听器(事件处理器之间没有严格区分)。
使用 addEventListener 方法注册一个事件监听器
EventTarget 对象的 addEventListener 方法注册一个事件侦听器,在指定事件发生时执行。格式如下。
target.addEventListener(type, callback [, options])
第一个参数是表示事件类型的字符串。(例如“点击”)。第二个参数指定回调函数作为事件处理程序。第三个可选选项在单独的页面上进行了描述。
例如,为id属性值为xxx的input标签使用addEventListener方法注册点击事件的事件监听器,写法如下。
<input type="button" value="button" id="xxx">
<script>
function butotnClick(){
console.log('Hello');
}
let button = document.getElementById('xxx');
button.addEventListener('click', butotnClick);
</script>
当点击事件发生时,回调函数butotnClick函数被调用。
要使用匿名函数注册事件侦听器,请编写:
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
let d = new Date();
console.log(d.toString());
});
</script>
同样,在使用箭头函数表达式时,写成如下。
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById("xxx");
button.addEventListener('click', () => {
console.log('Hello');
});
</script>
两种方法都产生基本相同的结果。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="mybutton">
<script>
function butotnClick(){
let d = new Date();
console.log(d.toString());
}
let button = document.getElementById('mybutton');
button.addEventListener('click', butotnClick);
</script>
</body>
</html>
单击该按钮可获取当前日期和时间并将其输出到控制台。
为同一目标上的同一事件注册多个事件侦听器
为 HTML 的属性值或从 DOM 获取的元素的属性注册事件处理程序时,同一事件只能注册一个事件处理程序,因为每个属性值或属性只能存储一个值。
相反,当使用 addEventListener 方法注册事件侦听器时,可以为同一目标上的同一事件注册多个事件侦听器。在这种情况下,当一个事件发生时,多个事件监听器将按照它们注册的顺序被调用。
<input type="button" value="button" id="xxx">
<script>
function dispHello(){
console.log('Hello');
}
function dispBye(){
console.log('Bye');
}
let button = document.getElementById('xxx');
button.addEventListener('click', dispHello);
button.addEventListener('click', dispBye);
</script>
当一个事件发生时,它会按照注册的顺序被调用,所以会先调用dispHello函数,然后是dispBye函数。
多次注册同一个事件监听器不会报错,但只会在第一次注册时调用。(但是,如果第三个选项不同,将处理不同的事件侦听器)。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="mybutton">
<script>
function dispHello(){
console.log('Hello');
}
function dispThankyou(){
console.log('Thank you');
}
function dispBye(){
console.log('Bye');
}
let button = document.getElementById('mybutton');
button.addEventListener('click', dispHello);
button.addEventListener('click', dispThankyou);
button.addEventListener('click', dispBye);
button.addEventListener('click', dispHello);
</script>
</body>
</html>
当点击显示的按钮时,依次调用三个注册的事件监听器,分别输出到控制台。请注意,dispHello 函数作为事件侦听器被注册了两次,但它仅在事件发生时被调用一次。
移除事件监听器
EventTarget 对象的 removeEventListener 方法注册一个事件侦听器,在指定事件发生时执行。格式如下。
target.removeEventListener(type, callback [, options])
为第一个和第二个(如果还指定了第三个,则为第三个)指定与注册要删除的事件侦听器时相同的参数。删除匹配的事件侦听器。
例如,要在事件监听器中使用 removeEventListener 方法来移除它自己的事件监听器:
<input type="button" value="button" id="xxx">
<script>
function butotnClick(){
console.log('Hello');
this.removeEventListener('click', butotnClick);
}
let button = document.getElementById('xxx');
button.addEventListener('click', butotnClick);
</script>
一旦事件侦听器被调用,事件侦听器就会在该函数内被释放。
使用匿名函数时的 removeEventListener 方法
如果您将匿名函数设置为事件侦听器,则使用 removeEventListener 方法移除事件侦听器可能会有点棘手。removeEventListener 方法的第二个参数必须是事件侦听器的函数名称,匿名函数缺少此名称。相反,指定一个可以引用当前正在执行的函数的 arguments.callee。
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Hello');
this.removeEventListener('click', arguments.callee);
});
</script>
但是,arguments.callee 现已弃用,不能在严格模式下使用。在使用 removeEventListener 方法时,建议定义一个单独的函数并将其注册为事件监听器,而不是匿名函数。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="mybutton">
<script>
function butotnClick(){
let num = Math.floor(Math.random() * 6) + 1;
console.log('骰子值为' + num + '');
this.removeEventListener('click', butotnClick);
}
let button = document.getElementById('mybutton');
button.addEventListener('click', butotnClick);
</script>
</body>
</html>
单击显示的按钮可获取 1 到 6 之间的随机值并将其打印到控制台。然后取消订阅为点击事件注册的事件监听器。(在事件侦听器中引用 this 是指触发事件的元素对象)。
调用回调函数时接收事件信息
当您将回调函数注册为事件侦听器时(这也适用于匿名函数和箭头函数表达式),事件作为参数传递一个 Event 对象,其中包含有关调用回调函数时发生的事件的信息。我会来. 如果要在函数中使用事件的信息,请在回调函数中描述参数。
<script>
function butotnClick(event){
console.log('Hello');
}
let button = document.getElementById('xxx');
button.addEventListener('click', butotnClick);
</script>
作为参数接收的 Event 对象中包含的信息因事件类型而异,但它包括诸如单击鼠标的位置和按下的键盘类型等信息。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="mybutton">
<script>
function butotnClick(event){
console.log('event.type:' + event.type);
console.log('event.target:' + event.target);
}
let button = document.getElementById('mybutton');
button.addEventListener('click', butotnClick);
</script>
</body>
</html>
单击显示的按钮时,有关发生的事件类型和事件发生的元素的信息将输出到控制台。
当用于为元素的属性注册事件处理程序或使用 addEventListener 方法注册事件侦听器的 JavaScript 代码位于 HTML 页面中描述目标元素的位置之前时,可能会导致错误。因此,您在阅读标头部分的 JavaScript 代码时需要格外小心。本节说明有关注册事件处理程序的代码的位置以及如何定位它的注意事项。
为什么会出现错误取决于您编写代码的位置
在这里,我们将以使用 addEventListener 注册事件监听器为例进行说明。使用属性注册事件处理程序也是如此。
至此,使用addEventListener方法为点击事件注册事件监听器的写法如下。
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Hello');
});
</script>
如果我们调换输入和脚本标签的顺序会发生什么?
<script>
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Hello');
});
</script>
<input type="button" value="button" id="xxx">
当访问 HTML 页面时,出现以下错误:
>> TypeError: Cannot read property 'addEventListener' of null
HTML页面下载完文件后,从页面开始解析(分析)HTML页面中描述的内容,构建DOM树。而如果 HTML 页面中有 <script> 标签,解析将停止,并执行 <script> 标签内的 JavaScript 代码。
在<script>标签内部,首先使用getElementById方法获取id属性为’xxx’的元素节点,但是由于这个元素写在<script>之后,所以还是解析,找不到。结果,变量 button 将包含 null。
然后下面的语句尝试执行addEventListener方法,但是目标变量button包含null,出现了之前的错误。
即使您在外部文件中编写 JavaScript 代码并加载该文件也是如此。即使使用<script>标签读取文件,也会暂时停止解析,读取文件,读取完文件后执行JavaScript代码,所以还没有找到尚未解析的input标签目标为空。
<script src="./main.js"></script>
<input type="button" value="button" id="xxx">
main.js
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Hello');
});
根据您编写这样的 JavaScript 代码的位置,会发生错误。下面描述了避免此错误的三种方法。
在 HTML 页面末尾编写 JavaScript 代码
第一种方法是先在 HTML 页面中编写目标元素,然后再编写 <script>,就像我们在前面的示例中所做的那样。
如前所述,HTML 页面是从页面顶部开始依次解析的。由于需要将元素的描述写在页面中显示的位置,如果将JavaScript代码写在元素之后,例如HTML页面末尾的</body>之前,则否发生错误。
如果对编写 JavaScript 代码的位置没有限制,这是最简单的方法。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="xxx">
<p>一个字符串将被输出到日志中。</p>
<!-- 将 JavaScript 代码放在最后 -->
<script src="./main.js"></script>
</body>
</html>
main.js
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Hello');
})
单击该按钮会向控制台打印“Hello”。
使用 DOMContentLoaded 事件
从这里开始,当您想在目标元素之前编写
<head>
<script>
document.addEventListener('DOMContentLoaded', function(){
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Thank you');
});
});
</script>
</head>
<body>
<input type="button" value="button" id="xxx">
</body>
当 DOMContentLoaded 事件触发时,您注册为事件侦听器的代码将运行,检索目标元素并为单击事件注册事件侦听器。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<script src="./main.js"></script>
</head>
<body>
<p>单击按钮</p>
<input type="button" value="button" id="xxx">
<p>一个字符串将被输出到日志中。</p>
</body>
</html>
main.js
document.addEventListener('DOMContentLoaded', function(){
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Thank you');
});
});
单击该按钮会向控制台打印“谢谢”。
使用加载事件
DOMContentLoaded 事件在文档对象上触发。文档对象没有 ondomcontentloaded 属性,因此您不能使用基于属性的方法来设置事件处理程序。如果 addEventListener 方法不可用,请改用在窗口对象上触发的加载事件。
DOMContentLoaded 事件在 DOM 树完成构建时触发,随后在所有资源(如图像和样式表)完成加载时触发 load 事件。按顺序,首先触发 DOMContentLoaded 事件,然后是加载事件。加载事件触发时,DOM 树已经完成,因此可以引用任何元素。
通过编写处理 HTML 页面中元素事件的 JavaScript 代码作为 window 对象的 onload 属性的事件处理程序,您可以将 JavaScript 代码的执行推迟到加载事件发生之后。
<head>
<script>
window.onload = function(){
let button = document.getElementById('xxx');
button.onclick = function(){
console.log('Thank you');
};
};
</script>
</head>
<body>
<input type="button" value="button" id="xxx">
</body>
当 load 事件触发时,您注册为事件处理程序的代码将执行,检索目标元素并为 click 事件注册事件处理程序。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<script src="./main.js"></script>
</head>
<body>
<p>单击按钮。。</p>
<input type="button" value="button" id="xxx">
<p>一个字符串将被输出到日志中。</p>
</body>
</html>
main.js
window.onload = function(){
let button = document.getElementById('xxx');
button.onclick = function(){
console.log('Thank you')
};
};
单击该按钮会向控制台打印“Thank you”。
在脚本标签中设置延迟属性
最后一种方法是在 script 标签上设置 defer 属性。此方法只能在加载包含 JavaScript 代码的外部文件时使用。
<head>
<script defer src="./main.js"></script>
</head>
<body>
<input type="button" value="button" id="xxx">
</body>
main.js
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Bye');
});
在由带有 defer 属性的脚本标签加载的外部 JavaScript 文件中编写的代码不会立即执行,而是在 DOM 树构建完成并触发 DOMContentLoaded 事件之前执行。
当代码执行时,DOM 树是完整的,您可以看到任何元素,因此您可以注册事件侦听器和事件处理程序,而无需添加任何额外的代码。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<script defer src="./main.js"></script>
</head>
<body>
<p>单击按钮</p>
<input type="button" value="button" id="xxx">
<p>一个字符串将被输出到日志中。</p>
</body>
</html>
main.js
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Bye');
});
单击按钮时向控制台打印“再见”。
当事件发生并调用已注册的事件处理程序或事件侦听器时,包含所发生事件信息的 Event 对象作为第一个参数传递。事件信息因发生的事件而异,但这里将说明如何获取所有事件共有的事件信息。
接收事件对象
当您为目标元素的属性注册事件处理程序时,以及当您使用 addEventListener 方法注册事件侦听器时,注册的回调函数将在事件发生时被调用。此时,存储发生事件信息的 Event 对象作为第一个参数传递。
<input type="button" value="button" id="xxx">
<script>
function butotnClick(event){
console.log('Hello');
}
let button = document.getElementById('xxx');
button.addEventListener('click', butotnClick);
</script>
实际上,对于click事件,传递的是继承Event对象的MouseEvent对象,对于keydown事件,传递的是继承Event对象的KeyboardEvent对象,根据事件类型不同,类型也不同。
MouseEvent 和 KeyboardEvent 对象包含不同的信息,但具体信息在各个事件描述页面上有解释。让我们看一下事件对象提供的可以为每个事件共同获取的信息。
可以使用 Event 对象获取的信息
可以通过引用 Event 对象的属性获取的信息包括以下内容。
属性名 | 説明 |
Event.bubbles | 事件是否冒泡 |
Event.cancelable | 事件是否可取消 |
Event.currentTarget | 注册事件处理程序的元素 |
Event.eventPhase | 事件的阶段(捕获阶段、目标面、冒泡阶段) |
Event.target | 事件发生的元素 |
Event.timeStamp | 元素创建和事件触发之间经过的时间(以毫秒为单位) |
Event.type | 表示事件类型的字符串 |
Event.isTrusted | 事件是否由用户交互引起 |
您可以通过引用在调用回调函数时作为参数传递的 Event 对象的属性来获取有关发生的事件的信息。
- Event.eventPhase可以引用的值有0:NONE,1:CAPTURING_PHASE,2:AT_TARGET,3:BUBBLING_PHASE
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>单击按钮。</p>
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.addEventListener('click', function(event){
console.log('bubbles :' + event.bubbles);
console.log('cancelable :' + event.cancelable);
console.log('currentTarget :' + event.currentTarget);
console.log('eventPhase :' + event.eventPhase);
console.log('target :' + event.target);
console.log('timeStamp :' + event.timeStamp);
console.log('type :' + event.type);
console.log('isTrusted :' + event.isTrusted);
});
</script>
</body>
</html>
单击按钮时,将引用发生的事件的信息并输出到控制台。
有关事件的信息存储在事件发生时传递给回调函数的 Event 对象中,但我们将解释 Event.currentTarget 和 Event.target,这两个可引用的属性之间的区别很难理解。。
Event.currentTarget 和 Event.target 属性之间的区别
注册事件处理程序或事件监听器后,注册的回调函数将在事件发生时被调用。此时,存储发生事件信息的 Event 对象作为第一个参数传递。
<input type="button" value="button" id="xxx">
<script>
function butotnClick(event){
console.log('Hello');
}
let button = document.getElementById('xxx');
button.addEventListener('click', butotnClick);
</script>
Event对象包含了很多关于事件的信息,其中Event.currentTarget和Event.target属性用于获取与事件发生的元素相关的信息。
属性名 | 説明 |
Event.currentTarget | 注册事件处理程序的元素 |
Event.target | 事件发生的元素 |
Event.currentTarget 属性包含注册事件处理程序的目标元素。例如,如果您已经注册了一个事件处理程序,它将是存储在按钮中的元素。
let button = document.getElementById('xxx');
button.addEventListener('click', butotnClick);
另一方面,Event.target 是事件实际发生的元素。如果您之前为其注册事件处理程序的按钮被单击,则 Event.target 属性还将包含 button 中包含的元素。在这种情况下,Event.currentTarget 和 Event.target 属性的值将相同。
考虑以下情况。div 元素包含一个输入元素作为子元素。
click 事件的事件处理程序在外部 div 元素上注册。如果你点击一个div元素,click事件会发生在div元素上,但是如果你点击input元素,它是div元素的子元素,click事件不仅会在input元素上发生,还会在input元素上发生在其父元素上。
由于事件处理程序注册在div元素上,Event.currentTarget属性包含div元素,但点击事件实际发生在input元素上,所以Event.target包含inputo元素。。这种情况导致 Event.currentTarget 和 Event.target 属性的值不同。
在引用之前,请仔细确定您需要哪个值,Event.currentTarget 属性还是 Event.target 属性。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<style type="text/css">
div {
width:300px;
background-color:#E5E5E5;
text-align:center;
padding:20px;
border:5px solid #8f8f8f;
}
</style>
</head>
<body>
<p>单击按钮</p>
<div id="outer">
<input type="button" value="button">
</div>
<script>
let div = document.getElementById('outer');
div.addEventListener('click', function(event){
console.log('currentTarget :');
console.log(event.currentTarget);
console.log('target :');
console.log(event.target);
console.log('-- --');
});
</script>
</body>
</html>
最初の外側の div 要素の部分をクリックしてください。 Event.currentTarget プロパティと Event.target プロパティの値をコンソールに出力しますが、この場合は同じ値となります。
接下来,单击作为 div 元素的子元素添加的 input 元素的一部分。将 Event.currentTarget 和 Event.target 属性的值打印到控制台,但在本例中 Event.currentTarget 属性是 div 元素,但 Event.target 属性是 input 元素。
当 HTML 页面中的某个元素发生事件时,事件不会仅在该元素上引发,而是会将事件传播到该元素的父元素,并在父元素上引发相同的事件。这里我们解释事件是如何通过 DOM 树传播的。
事件传播机制
例如,考虑以下 HTML 页面:
<html>
<head></head>
<body>
<p>Stopwatch</p>
<div>
<input type="button" value="start" id="btn1">
<input type="button" value="stop" id="btn2">
</div>
</body>
</html>
让我们看看单击此 HTML 页面中的“开始”按钮时如何触发和传播单击事件。
捕获阶段
单击 HTML 页面中的“开始”按钮时,最顶层的对象 Window 对象首先会触发单击事件。然后 click 事件依次在 Document 对象、html 元素、body 元素、div 元素和 DOM 树上触发。
这个阶段称为 捕获阶段。
然而,在捕获阶段发生的事件大多不被使用。如果您为元素属性或元素属性注册事件处理程序,则在捕获阶段发生事件时不会调用事件处理程序。
当使用 addEventListener 方法注册事件侦听器时,在捕获阶段引发的事件仅在第三个参数为 true 或 {capture: true} 时调用事件侦听器。
button.addEventListener('click', butotnClick, true);
button.addEventListener('click', butotnClick, {capture: true});
第三个参数是可选的,默认为 false。因此,如果不显式指定,即使使用addEventListener方法注册了事件监听器,捕获阶段发生的事件也不会调用该事件监听器。
目标阶段
在捕获阶段之后,点击事件将在实际触发该事件的元素上触发。这个阶段称为 目标阶段。
当目标阶段发生事件时,将调用为该事件注册的所有事件处理程序和事件侦听器。
冒泡阶段
在target阶段之后,点击事件从事件发生元素的父元素div元素到body元素、html元素、Document对象、Window对象依次产生,在DOM树中向上移动。去。这个阶段称为 冒泡阶段。
但是,如果事件没有发生在Window对象或Document对象中,则可能取决于它前面的html元素。
为事件注册的事件处理程序和事件侦听器也会为冒泡阶段发生的事件调用,但少数事件除外。由于 focus 和 blur 事件的 event.bubbles 属性为 false ,因此事件不会通过冒泡阶段传播。
这样,例如,当HTML页面中的某个元素发生事件时,通常在事件发生在目标阶段实际发生的元素上之后,DOM树从冒泡阶段实际发生的元素到Window 对象上升到其父元素,并且相同的事件发生在沿路径的元素和对象上。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<style type="text/css">
div {
background-color:#E5E5E5;
border:5px solid #8f8f8f;
}
#outer{
width:300px;
}
#inner{
margin:20px;
padding:20px;
text-align:center;
border-color: #2740bc;
}
#btn {
border-radius: 5px;
background: #2a2b71;
color: #fff;
padding: 8px 15px;
}
</style>
</head>
<body>
<p>单击按钮。</p>
<div id="outer">
<div id="inner">
<input type="button" value="button" id="btn">
</div>
</div>
<script>
let outer = document.getElementById('outer');
let inner = document.getElementById('inner');
let btn = document.getElementById('btn');
outer.addEventListener('click', function(){
console.log('outer');
});
inner.addEventListener('click', function(){
console.log('inner');
});
btn.addEventListener('click', function(){
console.log('btn');
});
</script>
</body>
在外层 div 元素里面有一个内层 div 元素,里面有一个 input 元素。每个元素都有一个为单击事件注册的事件侦听器。这次,addEventListener 方法省略了第三个参数,因此事件监听器不会在捕获阶段的事件发生时被调用。
首先尝试单击输入元素。这不仅会在输入元素上调用事件侦听器,还会在父元素内的 div 元素上调用事件侦听器,还会在父元素外的 div 元素上调用事件侦听器。
现在尝试单击内部 div 元素。然后调用外部 div 元素的事件侦听器,然后调用实际触发事件的内部 div 元素的事件侦听器。
对捕获阶段引发的事件调用事件侦听器
要为捕获阶段引发的事件调用事件侦听器,请在使用 addEventListener 方法注册事件侦听器时指定 true 或 {capture: true} 作为第三个参数。
button.addEventListener('click', butotnClick, true);
button.addEventListener('click', butotnClick, {capture: true});
如果第三个参数只是 true 或 false,它决定是否应该在捕获阶段对事件调用事件侦听器。如果省略第三个参数,则默认值为 false。您还可以将 {capture: true} 指定为第三个参数的对象值。
如果在捕获阶段设置事件调用事件监听器,冒泡阶段的事件将不再调用事件监听器。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<style type="text/css">
div {
background-color:#E5E5E5;
border:5px solid #8f8f8f;
}
#outer{
width:300px;
}
#inner{
margin:20px;
padding:20px;
text-align:center;
border-color: #2740bc;
}
#btn {
border-radius: 5px;
background: #2a2b71;
color: #fff;
padding: 8px 15px;
}
</style>
</head>
<body>
<p>单击按钮</p>
<div id="outer">
<div id="inner">
<input type="button" value="button" id="btn">
</div>
</div>
<script>
let outer = document.getElementById('outer');
let inner = document.getElementById('inner');
let btn = document.getElementById('btn');
outer.addEventListener('click', function(){
console.log('outer');
}, true);
inner.addEventListener('click', function(){
console.log('inner');
}, true);
btn.addEventListener('click', function(){
console.log('btn');
}, true);
</script>
</body>
</html>
在外层 div 元素里面有一个内层 div 元素,里面有一个 input 元素。每个元素都有一个为单击事件注册的事件侦听器。这次,将 addEventListener 方法的第三个参数设置为 true,因此事件监听器将在捕获阶段的事件发生时被调用。
首先尝试单击输入元素。然后首先在外部 div 元素上调用事件侦听器,然后是内部 div 元素,最后是实际触发事件的 input 元素。
现在尝试单击内部 div 元素。然后调用外部 div 元素的事件侦听器,然后调用实际触发事件的内部 div 元素的事件侦听器。
当 HTML 页面中发生事件时,该事件将传播到父元素,但您可以停止事件传播,使其不再传播。您还可以为同一目标上的同一事件注册多个事件侦听器,但在此过程中您可以阻止它们调用其他尚未调用的事件侦听器。本节介绍如何取消事件传播。
停止传播事件
可以使用 Event 对象的 stopPropagation 方法停止事件传播。格式如下。
event.stopPropagation()
例如,如果此方法在触发事件并被调用的事件侦听器中执行,它会阻止事件的进一步传播(无论是在捕获阶段还是冒泡阶段)。
你实际上会这样写:调用事件时,对作为参数传递的 Event 对象执行 stopPropagation 方法。
let target = document.getElementById('xxx');
target.addEventListener('click', function(event){
console.log('Hello');
event.stopPropagation();
});
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<style type="text/css">
div {
background-color:#E5E5E5;
border:5px solid #8f8f8f;
}
#outer{
width:300px;
}
#inner{
margin:20px;
padding:20px;
text-align:center;
border-color: #2740bc;
}
#btn {
border-radius: 5px;
background: #2a2b71;
color: #fff;
padding: 8px 15px;
}
</style>
</head>
<body>
<p>单击按钮</p>
<div id="outer">
<div id="inner">
<input type="button" value="buttonA" id="btnA">
<input type="button" value="buttonB" id="btnB">
</div>
</div>
<script>
let outer = document.getElementById('outer');
let inner = document.getElementById('inner');
let btna = document.getElementById('btnA');
let btnb = document.getElementById('btnB');
outer.addEventListener('click', function(){
console.log('outer');
});
inner.addEventListener('click', function(event){
console.log('inner');
event.stopPropagation();
});
btna.addEventListener('click', function(){
console.log('buttonA');
});
btnb.addEventListener('click', function(event){
console.log('buttonB');
event.stopPropagation();
});
</script>
</body>
</html>
外部 div 元素内有两个输入元素。每个input元素注册了两个事件监听器,stopPropagation方法在第一个input元素的第一个事件监听器中执行。在第二个输入元素的第一个事件侦听器中,我们调用了 stopImmediatePropagation 方法。
尝试先单击左侧的输入元素。由于我们在调用的第一个事件侦听器中运行 stopPropagation 方法,它不会将事件传播到父元素。但是执行了同一个元素上同一个事件的事件监听器,所以第二个事件监听器也被调用了。
现在尝试单击右侧的输入元素。由于我们在右侧输入元素上调用的事件侦听器中执行 stopPropagation 方法,因此将不再传播点击事件。
停止调用为同一事件注册的其他事件侦听器
您可以使用 Event 对象的 stopImmediatePropagation 方法来停止调用为同一事件注册但尚未被调用的其他事件侦听器。格式如下。
event.stopImmediatePropagation()
使用 addEventListener 方法注册事件侦听器时,可以为同一目标上的同一事件注册多个事件侦听器。当事件发生时,事件侦听器将按照它们注册的顺序被调用。
在已触发和调用的事件侦听器中执行 stopImmediatePropagation 方法可防止为同一事件注册但尚未调用的任何事件侦听器被调用。此外,不会执行到父元素的事件传播,就像执行 stopPropagation 方法时一样。
实际上会这样写:调用事件时,对作为参数传递的 Event 对象执行 stopImmediatePropagation 方法。
let target = document.getElementById('xxx');
target.addEventListener('click', function(event){
console.log('Hello');
event.stopImmediatePropagation();
});
target.addEventListener('click', function(event){
console.log('Bye');
});
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
<style type="text/css">
div {
background-color:#E5E5E5;
border:5px solid #8f8f8f;
}
#outer{
width:300px;
}
#inner{
margin:20px;
padding:20px;
text-align:center;
border-color: #2740bc;
}
#btn {
border-radius: 5px;
background: #2a2b71;
color: #fff;
padding: 8px 15px;
}
</style>
</head>
<body>
<p>单击按钮。</p>
<div id="outer">
<div id="inner">
<input type="button" value="buttonA" id="btnA">
<input type="button" value="buttonB" id="btnB">
</div>
</div>
<script>
let outer = document.getElementById('outer');
let btna = document.getElementById('btnA');
let btnb = document.getElementById('btnB');
outer.addEventListener('click', function(){
console.log('outer');
});
btna.addEventListener('click', function(event){
console.log('ActionA1');
event.stopPropagation();
});
btna.addEventListener('click', function(){
console.log('ActionA2');
});
btnb.addEventListener('click', function(event){
console.log('ActionB1');
event.stopImmediatePropagation();
});
btnb.addEventListener('click', function(){
console.log('ActionB2');
});
</script>
</body>
</html>
外部 div 元素内有两个输入元素。每个input元素注册了两个事件监听器,stopPropagation方法在第一个input元素的第一个事件监听器中执行。在第二个输入元素的第一个事件侦听器中,我们调用了 stopImmediatePropagation 方法。
尝试先单击左侧的输入元素。由于我们在调用的第一个事件侦听器中运行 stopPropagation 方法,它不会将事件传播到父元素。但是执行了同一个元素上同一个事件的事件监听器,所以第二个事件监听器也被调用了。
现在尝试单击左侧的输入元素。由于我们在调用的第一个事件侦听器中执行 stopImmediatePropagation 方法,它也会停止将事件传播到父元素,并且同一元素上仍在执行的同一事件的任何事件侦听器也将被调用。
当你在浏览器中打开一个 HTML 页面时,有一些默认的行为,比如点击一个链接导航到链接的页面,点击一个复选框来勾选它,旋转鼠标滚轮滚动屏幕,这些都是被设置的。您可以使用 Event 对象的 preventDefault 方法取消浏览器在触发事件时为事件设置的默认行为。本节介绍如何取消事件的默认行为。
取消默认行为
您可以使用 Event 对象的 preventDefault 方法来阻止事件的默认行为。格式如下。
event.preventDefault()
并非所有活动都可以取消。只有 Event.cancelable 属性值为 true 的事件才是可取消的。
你实际上会这样写:
let target = document.getElementById('xxx');
target.addEventListener('click', function(event){
event.preventDefault();
});
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>目前不可更改</p>
<div>
<input type="checkbox" id="checkA">
<label for="checkA">Java</label>
<input type="checkbox" id="checkB">
<label for="checkB">PHP</label>
</div>
<script>
let checkb = document.getElementById('checkB');
checkb.addEventListener('click', function(event){
alert('无法更改');
event.preventDefault();
});
</script>
</body>
</html>
我有两个输入元素。第二个输入元素为点击事件注册一个事件监听器,当事件发生时显示一个警告,然后执行 preventDefault 方法来取消默认行为。
首先尝试单击第一个输入元素。单击具有默认行为的复选框可将其打开和关闭。
现在尝试单击第二个输入元素。单击事件的事件侦听器被调用以取消显示警报后选中和取消选中复选框的默认行为。所以点击这个输入元素不会打开和关闭它。
事件由用户在浏览器中查看 HTTP 页面的操作触发,但您可以通过编程方式创建新事件以在指定目标上触发事件。本节介绍如何从代码生成事件。
创建一个新事件
首先创建一个新事件。使用 Event 对象的构造函数来创建它。
new Event(eventtype[, option])
在第一个参数中指定一个表示事件类型的字符串。指定 ‘click’ 或 ‘mousedown’ 以创建现有事件。创建自定义事件时指定任何名称。
可选的第二个参数指定一个具有以下三个值的对象:
bubbles 默认值 false
cancelable 默认值 false
composed 默认值 false
bubbles是冒泡阶段是否传播事件,cancelable是事件是否可以取消,composed的细节不知道。将其指定为对象,例如 {bubbles: true, cancelable: false}。
例如,要创建一个新的点击事件,写:
let e = Event('click');
提出一个事件
EventTarget 对象的 dispatchEvent 方法触发指定为目标目标的参数的事件。格式如下。
target.dispatchEvent(event)
为参数指定一个事件对象。
比如产生一个点击事件,这样写。
let e = Event('click');
let target = document.getElementById('xxx');
target.dispatchEvent(e);
通过引用Event.isTrusted属性,可以判断产生的事件是用户操作引起的,还是dispatchEvent方法的代码引起的。如果这是真的,那是由于用户交互。
示例代码
请看下面的示例。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>请点击按钮</p>
<div>
<input type="button" id="btnA" value="buttonA">
<input type="button" id="btnB" value="buttonB">
</div>
<script>
let btnA = document.getElementById('btnA');
let btnB = document.getElementById('btnB');
btnA.addEventListener('click', function(event){
console.log('buttonA:' + event.isTrusted);
let newevent = new Event('click');
btnB.dispatchEvent(newevent);
});
btnB.addEventListener('click', function(event){
console.log('buttonB:' + event.isTrusted);
});
</script>
</body>
</html>
我有两个输入元素。第一个输入元素的点击事件的事件侦听器创建一个点击事件并在第二个输入元素上触发该事件。
当你点击第一个input元素时,会调用第一个input元素的事件监听器,但是由于第二个input元素的click事件是在其中产生的,所以会调用第二个input元素的事件监听器。
第一个输入元素的事件侦听器由用户交互调用,因此显示 true ,第二个输入元素的事件侦听器由代码触发的事件调用,因此显示 false …
注意,当你点击第二个input元素时,第二个input元素的事件监听器会被调用,但是这次会显示true,因为是用户的交互。