原文网址:JS--事件(Event)--机制/原理_IT利刃出鞘的博客-CSDN博客
说明
本文介绍JavaScript中的事件的机制。包括:事件的捕获与冒泡,事件的流程。
官网
事件大全:事件参考 | MDN
JavaScript事件介绍
事件 是某事发生的信号。所有的 DOM 节点都生成这样的信号(但事件不仅限于
DOM)。
我们也可以自定义事件。
常用的事件
鼠标事件
键盘事件
表单(form)元素事件
Document 事件
CSS 事件
说明
JavaScript 事件触发有三个阶段。
我们可通过事件对象的 eventPhase 属性,得知事件处于哪个阶段。eventPhase 为一个正整数,其定义可在 Event interface 查阅到。本处贴出:
const unsigned short CAPTURING_PHASE = 1; const unsigned short AT_TARGET = 2; const unsigned short BUBBLING_PHASE = 3;
事件捕获与冒泡
本处以下边这个HTML为例进行说明
<html> <head> <title>事件捕获</title> </head> <body> <div>click</div> </body> </html>
事件捕获:从启动事件的元素节点开始,逐层往下传递,直到最下层节点,也就是div节点。
事件冒泡:从最底层的元素节点开始,逐层向上传递,直到最上层节点。
示例1:冒泡阶段处理事件
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>This is title</title> <style> body * { margin: 10px; border: 1px solid blue; } </style> </head> <body> <form id="id-form">FORM <div id="id-div">DIV <p id="id-p">P</p> </div> </form> <script> let form = document.getElementById('id-form'); form.addEventListener('click', (ev => { console.log('form. eventPhase:' + ev.eventPhase); })) let div = document.getElementById('id-div'); div.addEventListener('click', (ev => { console.log('div. eventPhase:' + ev.eventPhase); })) let p = document.getElementById('id-p'); p.addEventListener('click', (ev => { console.log('p. eventPhase:' + ev.eventPhase); })) </script> </body> </html>
测试:用鼠标点击“P”所在的框
示例2:冒泡阶段处理事件
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>This is title</title> <style> body * { margin: 10px; border: 1px solid blue; } </style> </head> <body> <form id="id-form">FORM <div id="id-div">DIV <p id="id-p">P</p> </div> </form> <script> let form = document.getElementById('id-form'); form.addEventListener('click', (ev => { console.log('form. eventPhase:' + ev.eventPhase); }), true) let div = document.getElementById('id-div'); div.addEventListener('click', (ev => { console.log('div. eventPhase:' + ev.eventPhase); }), true) let p = document.getElementById('id-p'); p.addEventListener('click', (ev => { console.log('p. eventPhase:' + ev.eventPhase); }), true) </script> </body> </html>
测试:用鼠标点击“P”所在的框
说明
可以通过 e.stopPropagation 中断事件的向下或向上传递。
这样一来,事件传播被中断了,剩下的 listener 不能接收到事件。
需要注意:stopPropagation 不能阻止同一节点的其他 listener 的执行 。
不要在没有需要的情况下停止事件传递
时间传递很方便,但是不要在没有真实需求时阻止它。只有需求要求如此,而且在架构上经过深思熟虑才能停止事件传递。
有时 event.stopPropagation() 会产生隐藏的陷阱,以后可能会成为问题。
例如:
通常,没有真正的必要去阻止冒泡。一项看似需要阻止冒泡的任务,可以通过其他方法解决。其中之一就是使用自定义事件,我们还可以将我们的数据写入一个处理程序中的 event 对象,并在另一个处理程序中读取该数据,这样我们就可以向父处理程序传递有关下层处理程序的信息。
示例
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>This is title</title> <style> body * { margin: 10px; border: 1px solid blue; } </style> </head> <body> <form id="id-form">FORM <div id="id-div">DIV <p id="id-p">P</p> </div> </form> <script> let form = document.getElementById('id-form'); form.addEventListener('click', (ev => { console.log('form. eventPhase:' + ev.eventPhase); })) let div = document.getElementById('id-div'); div.addEventListener('click', (ev => { console.log('div. eventPhase:' + ev.eventPhase); ev.stopPropagation(); })) let p = document.getElementById('id-p'); p.addEventListener('click', (ev => { console.log('p. eventPhase:' + ev.eventPhase); })) </script> </body> </html>
测试: 用鼠标点击“P”所在的框
可见:停止之后,外层的listener就接收不到事件了。
说明
许多事件会自动触发浏览器执行某些行为。例如:
有时我们不想要这种自定义的行为,想要自定义自己的行为,这时我们可以取消这个默认行为。
有两种方式来告诉浏览器我们不希望它执行默认行为:
示例
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>This is title</title> </head> <body> <a href="https://knife.blog.csdn.net/">这是常规链接</a><br> <a href="https://knife.blog.csdn.net/" onclick="return false">这是return false</a><br> <a href="https://knife.blog.csdn.net/" onclick="event.preventDefault()">这是event.preventDefault()</a> </body> </html>
测试
可见:阻止默认行为的下边那两个链接点击之后没反应;没有阻止默认行为的那个链接点击后会跳转。