<body> <div id="wrap"> <p class="hint"> <a href="#">Click Me</a> </p> </div> </body>如果给每个标签都定义事件,当我们点击其中的
<a>
标签时,会发现绑定在 <div>
和 <p>
标签上的事件也被触发了,这到底是为什么呢?为了解答这一问题,微软和网景两公司提出了两种不同的概念,事件捕获与事件冒泡:提示:上面提到的目标节点指的是触发事件的节点。
后来,W3C 为了统一标准,采用了一个折中的方式,即将事件捕获与事件冒泡合并,也就是现在的“先捕获后冒泡”,如下图所示:
图:事件捕获与事件冒泡
<a>
标签,则该事件将通过 document -> div -> p -> a
的顺序传递到 <a>
标签。<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript</title> <style type="text/css"> div, p, a { padding: 15px 30px; display: block; border: 2px solid #000; background: #fff; } </style> </head> <body> <div id="wrap">DIV <p class="hint">P <a href="#">A</a> </p> </div> <script> function showTagName() { alert("事件捕获: " + this.tagName); } var elems = document.querySelectorAll("div, p, a"); for (let elem of elems) { elem.addEventListener("click", showTagName, true); } </script> </body> </html>运行上面的代码,单击最内层的
<a>
标签,运行结果如下图所示:
图:事件捕获演示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript</title> <style type="text/css"> div, p, a { padding: 15px 30px; display: block; border: 2px solid #000; background: #fff; } </style> </head> <body> <div onclick="alert('事件冒泡: ' + this.tagName)">DIV <p onclick="alert('事件冒泡: ' + this.tagName)">P <a href="#" onclick="alert('事件冒泡: ' + this.tagName)">A</a> </p> </div> </body> </html>运行上面的代码,单击最内层的
<a>
标签,运行结果如下图所示:
图:事件冒泡演示
event.stopPropagation();
注意:stopPropagation() 会阻止事件捕获和事件冒泡,但是无法阻止标签的默认行为,例如点击链接任然可以打开对应网页。
示例代码如下:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript</title> <style type="text/css"> div, p, a { padding: 15px 30px; display: block; border: 2px solid #000; background: #fff; } </style> </head> <body> <div id="wrap">DIV <p class="hint">P <a href="#">A</a> </p> </div> <script> function showAlert(event) { alert("您点击了 "+ this.tagName + " 标签"); event.stopPropagation(); } var elems = document.querySelectorAll("div, p, a"); for(let elem of elems) { elem.addEventListener("click", showAlert); } </script> </body> </html>此外,您也可以使用 stopImmediatePropagation() 方法来阻止同一节点的同一事件的其它事件处理程序,例如为某个节点定义了多个点击事件,当事件触发时,这些事件会按定义顺序依次执行,如果其中一个事件处理程序中使用了 stopImmediatePropagation() 方法,那么剩下的事件处理程序将不再执行。
event.stopImmediatePropagation();
示例代码如下:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript</title> <style type="text/css"> div, p, a { padding: 15px 30px; display: block; border: 2px solid #000; background: #fff; } </style> </head> <body> <div onclick="alert('您点击了 ' + this.tagName + ' 标签')">DIV <p onclick="alert('您点击了 ' + this.tagName + ' 标签')">P <a href="#" id="link">A</a> </p> </div> <script> function sayHi() { alert("事件处理程序 1"); event.stopImmediatePropagation(); } function sayHello() { alert("事件处理程序 2"); } // 为 id 为 link 的标签定义多个点击事件 var link = document.getElementById("link"); link.addEventListener("click", sayHi); link.addEventListener("click", sayHello); </script> </body> </html>
event.preventDefault();
示例代码如下:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript</title> </head> <body> <a href="http://task.lmcjl.com/" id="link">链接</a> <script> var link = document.getElementById("link"); link.addEventListener('click', function(event){ event.preventDefault(); // 阻止链接跳转 }); </script> </body> </html>
注意:IE9 及以下的版本不支持 preventDefault() 方法,对于 IE9 及以下的浏览器您可以使用 event.returnValue = false;
。
本文链接:http://task.lmcjl.com/news/17903.html