如果删除DOM元素,以该元素开头的事件是否会继续冒泡?

问题描述 投票:19回答:3

如果删除用于启动事件气泡的DOM元素,或者由其子级启动事件气泡的DOM元素,如果删除该元素,它会继续气泡吗?

例如,假设您有一个表格,并且想检测表格单元格上的点击事件。另一段JS执行了AJAX请求,一旦请求完成,最终将完全替换该表。

如果我单击表格,并且在表格被成功完成的AJAX请求替换后立即发生了什么?我问是因为我看到了一些点击事件似乎没有冒泡的行为,但是很难复制。

我正在表的父元素上观看事件(而不是将事件附加到每个TD上,并且有时似乎没有达到它。

EDIT:再次遇到此问题,并最终找到根源。根本不是一个冒泡事件!请参阅下面的详细信息。

javascript dom dom-events event-bubbling
3个回答
24
投票

经验:这取决于您使用的浏览器; IE取消了该事件,其他所有事件(据我所知)仍在继续。请参阅下面的测试页和讨论。

理论上: Andy E's head有助于found认为DOM2 says the event should continue,因为冒泡应基于树的initial状态。因此,大多数人的行为是正确的,IE本身就在这里。让奎尔感到惊讶。

但是:这是否与您看到的内容有关,确实是另一个问题。您正在观察对表的父元素的单击,并且您怀疑的是很少有,当您单击表时,会出现带有Ajax补全的竞争条件,该条件会替换表并导致点击丢失。 Java解释器中不存在这种竞争条件,因为目前,浏览器上的Javascript是单线程的。 (不过,工作线程即将到来-哇!)但是从理论上讲,单击可能发生并由浏览器中的非Javascript UI线程排队,然后ajax可以完成并替换元素,然后排队的UI事件被处理,根本不会发生,也不会冒泡,因为元素已不再具有父元素,因此已被移除。能否实际发生将取决于浏览器的实现。如果您在任何开放源代码浏览器中看到它,则可以查看它们的源以排队UI事件以供解释器处理。但这与实际删除带有代码within事件处理程序的元素不同,如下所示。

确实冒泡持续性方面的经验结果:

经过测试的Chrome 4和Safari 4(例如WebKit),Opera 10.51,Firefox 3.6,IE6,IE7和IE8。当您删除元素时,IE是唯一一个取消事件的元素(并且在各个版本中保持一致),其他元素都没有。无论您使用的是DOM0处理程序还是更现代的处理程序,似乎都没有关系。

UPDATE:

在测试中,IE9和IE10继续该事件,因此IE不符合规范的行为在IE8处停止。使用DOM0处理程序的测试页:

<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> <title>Test Page</title> <style type='text/css'> body { font-family: sans-serif; } #log p { margin: 0; padding: 0; } </style> <script type='text/javascript'> window.onload = pageInit; function pageInit() { var parent, child; parent = document.getElementById('parent'); parent.onclick = parentClickDOM0; child = document.getElementById('child'); child.onclick = childClickDOM0; } function parentClickDOM0(event) { var element; event = event || window.event; element = event.srcElement || event.target; log("Parent click DOM0, target id = " + element.id); } function childClickDOM0(event) { log("Child click DOM0, removing"); this.parentNode.removeChild(this); } function go() { } var write = log; function log(msg) { var log = document.getElementById('log'); var p = document.createElement('p'); p.innerHTML = msg; log.appendChild(p); } </script> </head> <body><div> <div id='parent'><div id='child'>click here</div></div> <hr> <div id='log'></div> </div></body> </html>

使用attachEvent / addEventListener处理程序的测试页(通过原型):

<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> <title>Test Page</title> <style type='text/css'> body { font-family: sans-serif; } #log p { margin: 0; padding: 0; } </style> <script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js'></script> <script type='text/javascript'> document.observe('dom:loaded', pageInit); function pageInit() { var parent, child; parent = $('parent'); parent.observe('click', parentClick); child = $('child'); child.observe('click', childClick); } function parentClick(event) { log("Parent click, target id = " + event.findElement().id); } function childClick(event) { log("Child click, removing"); this.remove(); } function go() { } var write = log; function log(msg) { $('log').appendChild(new Element('p').update(msg)); } </script> </head> <body><div> <div id='parent'><div id='child'>click here</div></div> <hr> <div id='log'></div> </div></body> </html>


5
投票
是的,它应该继续传播。除了target属性外,事件与它们触发的事件没有真正的联系。当您删除元素时,传播事件的内部代码不应具有任何“意识”,即原始元素已从可见文档中移出。

5
投票
自我最初发布此问题以来已经有一段时间了。尽管T.J. Crowder的回答非常有启发性(就像Andy E的回答一样),并且告诉我[应该]起作用,但我仍然发现问题。我将其搁置了一段时间,但是今天当我在另一个Web应用程序中再次遇到相同的问题时再次进行了讨论。
© www.soinside.com 2019 - 2024. All rights reserved.