Mat*_*att 19 javascript dom javascript-events event-bubbling
如果我删除用于启动事件气泡的DOM元素,或者其子项启动事件气泡,我应该期待什么行为?如果元素被删除,它会继续冒泡吗?
例如 - 假设您有一个表,并希望检测表格单元格上的单击事件.JS的另一部分执行了一个AJAX请求,一旦请求完成,它将最终完全替换表.
如果我单击表格会立即在表格被成功完成AJAX请求取代后会发生什么?我问,因为我看到一些行为,其中点击事件似乎没有冒泡 - 但很难复制.
我正在观看桌子的父元素上的事件(而不是将事件附加到每个TD),并且它有时似乎没有达到它.
编辑:再次遇到这个问题,最后得到了它的根源.根本不是一个冒泡的问题!请参阅下面的答案了解详情.
T.J*_*der 25
经验:这取决于您使用的浏览器; IE取消了该事件,其他一切(据我所知)继续它.请参阅下面的测试页和讨论.
从理论上讲: 安迪·E公司的头很有帮助发现该DOM2说,事件应该继续,因为起泡,应根据该初始树的状态.所以多数人的行为是正确的,IE就在这里.Quelle惊喜.
但是:这与你所看到的有关,确实是另一个问题.你正在观察表的父元素的点击,你怀疑的是很少,当你点击表时,有一个竞争条件,Ajax完成取代了表,点击就会丢失.Javascript解释器中不存在竞争条件,因为目前浏览器上的Javascript是单线程的.(工作线程即将到来 - 不管怎么说!)但理论上,点击可能会发生并被浏览器中的非Javascript UI线程排队,然后ajax可以完成并替换元素,然后排队的UI事件得到处理,根本不发生或不起泡,因为该元素不再具有父项,已被删除.是否能真正发生将取决于一个许多浏览器执行.如果您在任何开源浏览器上看到它,您可能会查看其源代码来排队UI事件以供解释器处理.但是,这不是真正的代码删除元素另当别论内的事件处理程序,因为我有以下.
鼓泡 - 继续方面的实证结果:
测试了Chrome 4和Safari 4(例如,WebKit),Opera 10.51,Firefox 3.6,IE6,IE7和IE8.当你删除元素时,IE是唯一一个取消该事件的人(并且在不同的版本中一直这样做),其他人都没有.无论您使用的是DOM0处理程序还是更现代的处理程序,似乎都无关紧要.
更新: 在测试中,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>
Run Code Online (Sandbox Code Playgroud)
使用attachEvent/ addEventListener处理程序测试页面(通过Prototype):
<!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>
Run Code Online (Sandbox Code Playgroud)
是的,它应该继续传播.除了target财产之外,事件对他们开除的事件没有真正的依恋.删除元素时,传播事件的内部代码不应该具有原始元素从可见文档中消失的"感知".
另外,使用removeChild不会立即删除元素,它只是将其从文档树中分离出来.只有在没有引用元素时才应删除/垃圾收集元素.因此,有可能仍然可以通过event.target属性引用该元素,甚至在被垃圾收集之前重新插入. 我没有尝试过,所以这只是猜测.
event.target.
被指定为冒泡的事件最初将以与非冒泡事件相同的事件流进行.事件被调度到其目标EventTarget,并且发现触发的任何事件侦听器.然后,冒泡事件将触发通过向上跟踪EventTarget的父链找到的任何其他事件侦听器,检查在每个连续的EventTarget上注册的任何事件侦听器.这种向上传播将持续到包括文档在内.在此阶段,不会触发注册为捕获者的EventListeners.在事件的初始分派之前,确定从事件目标到树顶部的EventTargets链.如果在事件处理期间对树进行修改,则事件流将基于树的初始状态继续进行.
自从我最初发布这个问题以来已经有一段时间了.虽然TJCrowder的回答非常有用(就像Andy E的那样),并告诉我它应该有效,但我仍然看到了一个问题.我把它搁置了一段时间,但今天在我在另一个Web应用程序中再次遇到同样的问题时重新访问它.
我玩了一段时间,我开始意识到如何每次都重复这个问题(至少在FF3.6和Chrome 8中).问题不是事件泡泡被取消,或者在删除DOM元素时丢失了.相反,问题是如果在 mousedown和mouseup 之间更改元素,则"click"不会触发.
根据Mozilla开发网络:
当用户单击元素时,将引发click事件.click事件将在mousedown和mouseup事件之后发生.
因此,当你有一个完全改变的DOM元素时,你可能会遇到这个问题.我错误地认为事件泡沫正在消失.只是如果你有一个经常更新的元素,你会更频繁地看到它(这是我的情况)并且不太可能将它作为侥幸传递.
进一步的测试(见例如上的jsfiddle)表明,如果一个点击,保存按钮并等待DOM元素改变,然后释放按钮,我们可以观察到(在jQuery的现场背景):
编辑:在IE8中测试.IE8触发鼠标按下了第一个节点,鼠标松开更新的节点,但确实在事实上火"点击",使用更新的节点作为事件源.
| 归档时间: |
|
| 查看次数: |
4488 次 |
| 最近记录: |