【问题标题】:event not bubbling like I think it should事件没有像我认为的那样冒泡
【发布时间】:2019-01-19 14:24:37
【问题描述】:

我在库存中有一个动态生成的项目页面。我正在尝试创建一个 onclick 事件,以便如果用户单击显示的项目信息或图像,事件侦听器将执行。我可以通过在 HTML 中添加 onclick="doSomething(this.id) 使其工作,但无法使用我见过的任何事件冒泡和事件委托教程中的方法使其工作。 项目图像和数据显示在单独的 HTML 表格中,每个项目一个。每个都有一个唯一的 id,它们都包含在一个容器 div 元素中。 addEventListener 被分配给 div,而不是每个表都有一个监听器。 似乎正在发生的是 img 元素 td 元素的点击事件触发器。 tr 或表格,如果我在单击表格元素之前非常小心地放置光标。无论我做什么,该事件似乎都不会冒泡。我应该能够让它在每个连续元素上触发,但有些东西正在停止传播。
当单击该表或任何后代元素时,我需要检索(表的)唯一 ID。

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 的直接后代的点击。

【问题讨论】:

  • “直接后代”——HTML 中没有任何其他类型的后代。
  • 您的问题似乎是一个简单的语法错误。
  • @quentin 说没有办法区分 div#1234 和 img 元素?我觉得这很好奇。他认为这不仅仅是“一个简单的语法错误”,而是他选择不让任何人了解的秘密
  • 重新思考和重新测试它可能根本不是冒泡的问题,但是由于堆叠顺序,img 和其他对象首先会遮挡 div(或表格)而不是看到点击。如果是这种情况,我可以更改逻辑并告诉用户单击图像。或者我可以使用 CSS 指针事件来操纵点击的曝光。使用 img 方法可能更聪明,但仍然希望有人澄清或确认。仅仅因为我可以让它工作,并不意味着它是正确的。
  • "@quentin 说没有办法区分 div#1234 和 img 元素?" - 我没那么说过。 div 是容器的孩子,图像是曾曾孙。他们都是直系后代。

标签: javascript events delegation


【解决方案1】:

我发现,如果我为 DOM 树的一个片段中的每个元素添加相同的侦听器,单击鼠标将触发每个元素的单击事件,从被单击的元素开始,沿着每个连续的元素传播(冒泡)。然后我可以测试每个节点的 className "item" 并在找到时读取它的 id。这会产生我想要的结果,但这意味着数百个元素被分配了同一个侦听器。它可能只有数百个指针,但并没有让我觉得效率很高

但是,如果我将侦听器仅添加到顶部元素,则单击事件只会触发侦听器一次,无论哪个元素实际收到了点击(例如,img 但不是它所在的 td,或者 td 所在的 tr,等等.)。我看到很多原因,在正常情况下这是一件好事,但它并不能满足我的需要。

考虑到这一点,我想出了以下解决方案。我将侦听器添加到顶部元素。然后处理程序测试 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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 1970-01-01
    • 2011-10-20
    • 2011-08-23
    • 1970-01-01
    相关资源
    最近更新 更多