事件没有像我认为的那样冒泡
event not bubbling like I think it should
我有一个动态生成的清单项目页面。我正在尝试创建一个 onclick 事件,这样如果用户单击显示的项目信息或图像,事件监听器就会执行。我可以通过在 HTML 中添加一个 onclick="doSomething(this.id) 来使其工作,但无法使用我拥有的任何事件冒泡和事件委托教程中的方法使其工作见过。
项目图像和数据在 dividual HTML table 中呈现,每个项目一个。每个都有一个唯一的 ID,它们都包含在一个容器 div 元素中。 addEventListener 分配给 div,而不是为每个 table 分配一个侦听器。
似乎正在发生的是 img 元素、td 元素的点击事件触发器。 tr 或 table,如果我在单击 table 元素之前非常小心地放置光标。无论我做什么,该事件似乎都不会冒泡。我应该能够让它在每个连续的元素上触发,但有些东西正在停止传播。
单击 table 或任何后代元素时,我需要检索唯一 ID(table)。
var theParent = document.querySelector('#container');
theParent.addEventListener("click", doSomething);
}
function doSomething(e) {
console.log(e.target.id) + " \r\n";
if (e.target !== e.currentTarget) {
var clickedItem = e.target.nodeName;
console.log(clickedItem);
}
}
<div id="container">
<table class="items" id="1234">
<tr>
<td>
<img src="path/to/item.jpg">
</td>
<td>
this is item 1234
</td>
</tr>
</table>
...
</div>
或
<div id="container">
<div class="items" id="1234">
<table>
<tr>
<td>
<img src="path/to/item.jpg">
</td>
<td>
this is item 1234
</td>
</tr>
</table>
</div>
...
</div>
我认为 if (e.target !== e.currentTarget) 应该为每个后代对象执行 console.log(clickedItem),但不包括 currentTarget。它没有,即使我删除了 if() 筛选。我想对此进行一些澄清,但更重要的是,我想修改 if 语句,使其仅对 currentTarget 的直接后代的点击为真。
我发现,如果我将相同的侦听器添加到 DOM 树的一个片段中的每个元素,单击一次鼠标将为每个元素触发一个单击事件,从单击的元素开始,依次向上移动元素(冒泡)。然后我可以测试每个节点的 className "item" 并在找到时读取它的 id。这会产生我想要的结果,但这意味着数百个元素被分配了同一个侦听器。可能只有数百个指针,但我觉得效率不高
但是,如果我将侦听器添加到顶部元素,则无论哪个元素实际收到点击(例如,img 但不是它所在的 td,或者 tr td 所在的 tr),单击事件只会触发一次侦听器, ETC。)。我看到很多原因,这在正常情况下是一件好事,但它不能满足我的需要。
经过深思熟虑,我想到了以下解决方案。我将侦听器添加到顶部元素。然后处理程序测试 e.target 是否具有 "item" 的类名,如果不是,它会遍历每个连续的父节点,直到找到具有类名 "item" 的节点,然后读取该节点的 ID (这是我要查找的库存项目编号)。
function doSomething(e) {
if(e.target !== e.currentTarget){
var el = e.target;
do {
el = el.parentNode;
} while (el.className !="item");
var clickedItem = el.id;
console.log("Clicked item id: " + clickedItem);
}
}
topofTree= document.querySelector('#container') ;
topofTree.addEventListener("click",doSomething) ;
<div id="container">
<table class="item" id="0064">
<tr>
<td><img src="/spiritmasks/images/MSK_spirit_mask_8.jpg" ></td>
<td>
<table>
<tr><td>Item ID:</td><td>0064</td></tr>
<tr><td>Display Name:</td><td>Spirit Mask #8</td></tr>
<tr><td>Description:</td><td></td></tr>
<tr><td>Type:</td><td>SPIRIT MASK</td></tr>
<tr><td>Location:</td><td>GALLERY</td></tr>
<tr><td>In Slide Show:</td><td>NO</td></tr>
<tr><td>Size:</td><td></td></tr>
<tr><td>Price:</td><td></td></tr>
<tr><td>Comments:</td><td></td></tr>
</table>
</td>
</tr>
</table>
</div>
我有一个动态生成的清单项目页面。我正在尝试创建一个 onclick 事件,这样如果用户单击显示的项目信息或图像,事件监听器就会执行。我可以通过在 HTML 中添加一个 onclick="doSomething(this.id) 来使其工作,但无法使用我拥有的任何事件冒泡和事件委托教程中的方法使其工作见过。
项目图像和数据在 dividual HTML table 中呈现,每个项目一个。每个都有一个唯一的 ID,它们都包含在一个容器 div 元素中。 addEventListener 分配给 div,而不是为每个 table 分配一个侦听器。
似乎正在发生的是 img 元素、td 元素的点击事件触发器。 tr 或 table,如果我在单击 table 元素之前非常小心地放置光标。无论我做什么,该事件似乎都不会冒泡。我应该能够让它在每个连续的元素上触发,但有些东西正在停止传播。
单击 table 或任何后代元素时,我需要检索唯一 ID(table)。
var theParent = document.querySelector('#container');
theParent.addEventListener("click", doSomething);
}
function doSomething(e) {
console.log(e.target.id) + " \r\n";
if (e.target !== e.currentTarget) {
var clickedItem = e.target.nodeName;
console.log(clickedItem);
}
}
<div id="container">
<table class="items" id="1234">
<tr>
<td>
<img src="path/to/item.jpg">
</td>
<td>
this is item 1234
</td>
</tr>
</table>
...
</div>
或
<div id="container">
<div class="items" id="1234">
<table>
<tr>
<td>
<img src="path/to/item.jpg">
</td>
<td>
this is item 1234
</td>
</tr>
</table>
</div>
...
</div>
我认为 if (e.target !== e.currentTarget) 应该为每个后代对象执行 console.log(clickedItem),但不包括 currentTarget。它没有,即使我删除了 if() 筛选。我想对此进行一些澄清,但更重要的是,我想修改 if 语句,使其仅对 currentTarget 的直接后代的点击为真。
我发现,如果我将相同的侦听器添加到 DOM 树的一个片段中的每个元素,单击一次鼠标将为每个元素触发一个单击事件,从单击的元素开始,依次向上移动元素(冒泡)。然后我可以测试每个节点的 className "item" 并在找到时读取它的 id。这会产生我想要的结果,但这意味着数百个元素被分配了同一个侦听器。可能只有数百个指针,但我觉得效率不高
但是,如果我将侦听器添加到顶部元素,则无论哪个元素实际收到点击(例如,img 但不是它所在的 td,或者 tr td 所在的 tr),单击事件只会触发一次侦听器, ETC。)。我看到很多原因,这在正常情况下是一件好事,但它不能满足我的需要。
经过深思熟虑,我想到了以下解决方案。我将侦听器添加到顶部元素。然后处理程序测试 e.target 是否具有 "item" 的类名,如果不是,它会遍历每个连续的父节点,直到找到具有类名 "item" 的节点,然后读取该节点的 ID (这是我要查找的库存项目编号)。
function doSomething(e) {
if(e.target !== e.currentTarget){
var el = e.target;
do {
el = el.parentNode;
} while (el.className !="item");
var clickedItem = el.id;
console.log("Clicked item id: " + clickedItem);
}
}
topofTree= document.querySelector('#container') ;
topofTree.addEventListener("click",doSomething) ;
<div id="container">
<table class="item" id="0064">
<tr>
<td><img src="/spiritmasks/images/MSK_spirit_mask_8.jpg" ></td>
<td>
<table>
<tr><td>Item ID:</td><td>0064</td></tr>
<tr><td>Display Name:</td><td>Spirit Mask #8</td></tr>
<tr><td>Description:</td><td></td></tr>
<tr><td>Type:</td><td>SPIRIT MASK</td></tr>
<tr><td>Location:</td><td>GALLERY</td></tr>
<tr><td>In Slide Show:</td><td>NO</td></tr>
<tr><td>Size:</td><td></td></tr>
<tr><td>Price:</td><td></td></tr>
<tr><td>Comments:</td><td></td></tr>
</table>
</td>
</tr>
</table>
</div>