单击事件不适用于内部标记元素

click event not working on inner tag elements

这是我正在使用的标记

<div class="checkout-row__form-column__billing">
  <div class="checkout-row__form-column__billing__title billing-collapse collapse-btn">
     <div class="checkout-row__form-column__billing__title__arrow">
       <i class="fa fa-chevron-right" aria-hidden="true"></i>
     </div>
   <h2>1. Billing Details</h2>
</div>
<div class="checkout-row__form-column__shipping__content shipping-collapse-content collapse-target"></div>
<div class="checkout-row__form-column__shipping">
  <div class="checkout-row__form-column__shipping__title shipping-collapse collapse-btn">
     <div class="checkout-row__form-column__shipping__title__arrow">
       <i class="fa fa-chevron-right" aria-hidden="true"></i>
     </div>
   <h2>2. Shipping Details</h2>
</div>
<div class="checkout-row__form-column__shipping__content shipping-collapse-content collapse-target"></div>

所有这些标记都包含在 div 中,class 为 checkout-row__form-column。 所以,我正在抓取父包装器,单击我将目标与 .collapse-btn 匹配。然后我 class 切换 .collapse-target 的兄弟姐妹。效果很好,除了问题,我无法通过。如果我点击内部元素,事件不会发生。

这是我的js

parent = document.querySelector('.checkout-row__form-column');
    parent.addEventListener('click', (e)=>{
      if (e.target.matches('.collapse-btn')) {
        e.stopPropagation();
        
        e.target.nextElementSibling.classList.toggle('hide');
      }
    });

使用这些代码,如果我不单击 i 元素或 h2,我可以切换 classes。如果我单击 e.target.

中的任意位置,我该如何编写我的 JavaScript 事件将被触发

非常感谢战友们的帮助。

您的代码仅检查 event.target 是否为 .collapse-btn 元素。您还需要检查单击的元素是否是 .collapse-btn 元素的后代元素。

为了达到预期的结果,您可以使用这两个条件来检查 event.target 是否是 .collapse-btn 或其任何后代。要检查后代元素,请使用通用选择器 *.

parent.addEventListener('click', (e) => {
  if (
       e.target.matches('.collapse-btn') || 
       e.target.matches('.collapse-btn *')
  ) {
     // code
  }
});

演示

以下片段显示了一个示例:

const parent = document.querySelector('.container');

parent.addEventListener('click', e => {  
  if (
      e.target.matches('.collapse-btn') ||
      e.target.matches('.collapse-btn *') 
  ) {
    parent.classList.toggle('active');
  }
});
.container {
  background: #eee;
  width: 120px;
  height: 120px;
}

.container.active {
  border: 2px solid;
}

.collapse-btn {
  background: #999;
  padding: 10px;
}

.collapse-btn span {
  background: #fc3;
  font-size: 1.3rem;
  cursor: pointer;
}
<div class="container">
  <div class="collapse-btn">
    <span>Click</span>
  </div>
</div>

您也可以将选择器放在一个数组中,然后使用 .some() 方法检查 event.target 是否匹配数组中的任何一个选择器。

const selectors = ['.collapse-btn', '.collapse-btn *'];

parent.addEventListener('click', e => {
  if (selectors.some(s => e.target.matches(s))) {
    // code
  }
});

演示

以下片段显示了一个示例:

const parent = document.querySelector('.container');

parent.addEventListener('click', e => {
  const selectors = ['.collapse-btn', '.collapse-btn *'];

  if (selectors.some(s => e.target.matches(s))) {
    parent.classList.toggle('active');
  }
});
.container {
  background: #eee;
  width: 120px;
  height: 120px;
}

.container.active {
  border: 2px solid;
}

.collapse-btn {
  background: #999;
  padding: 10px;
}

.collapse-btn span {
  background: #fc3;
  font-size: 1.3rem;
  cursor: pointer;
}
<div class="container">
  <div class="collapse-btn">
    <span>Click</span>
  </div>
</div>

备选方案

不使用 .matches() 方法,而是使用 Element.closest() and Node.contains() 方法的组合来检查 event.target.collapse-btn 元素还是 .collapse-btn 元素的子元素.collapse-btn 元素。

为此,您需要执行两个步骤:

  1. 您首先需要获取 .collapse-btn,它是 event.target 的最近祖先。

  2. 之后,您需要检查 event.target 是否是在步骤 1 中选择的按钮的后代。

代码:

parent.addEventListener('click', (e) => {
   const targetCollapseBtn = e.target.closest('.collapse-btn');

   if (targetCollapseBtn && targetCollapseBtn.contains(e.target)) {
       ...
   }
});

如果event.target.collapse-btn本身,那么

e.target.closest('.collpase-btn')

将 return e.target,即 .collapse-btn

targetCollapseBtn.contains(e.target)

也将 return 为真,因为 .contains() 方法 return 为真,即使作为参数传递给它的节点与 .contains() 方法被调用。

因此,以这种方式使用 .closest().contains() 方法涵盖了两种用例,即单击 .collapse-btn 或单击其任何后代元素时。

演示

以下代码片段显示了一个简单示例:

const parent = document.querySelector('.container');

parent.addEventListener('click', e => {
  const targetCollapseBtn = e.target.closest('.collapse-btn');

  if (targetCollapseBtn && targetCollapseBtn.contains(e.target)) {
    parent.classList.toggle('active');
  }
});
.container {
  background: #eee;
  width: 120px;
  height: 120px;
}

.container.active {
  border: 2px solid;
}

.collapse-btn {
  background: #999;
  padding: 10px;
}

.collapse-btn span {
  background: #fc3;
  font-size: 1.3rem;
  cursor: pointer;
}
<div class="container">
  <div class="collapse-btn">
    <span>Click</span>
  </div>
</div>