阻止子元素点击触发父元素事件。

3

我在 li 标签上绑定了一个点击事件,然后在该标签中又有一个嵌套的子 li

点击父级 li 时一切正常。但是点击嵌套或子 li 时,会触发父级 li 的点击事件。

我使用了 event.stopPropagation() 方法,但在我的情况下它不起作用。

$("li").on("click",function() {
  console.log(this.firstChild.textContent)
})
$('#testUl > li').on('click', function(e) {
  e.stopPropagation();
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<ul id="testUl">
  <li>
    <a href="#">Test A</a>
    <div class="innerUl">
      <ul>
        <li>Inner A</li>
        <li>Inner B</li>
        <li>Inner C</li>
      </ul>
    </div>
  </li>
</ul>


$('#testUl > li') 可能是错误的选择器。如果您想要对父元素和子元素使用相同的函数,请使用 $('#testUI li')。 - Dov Rine
你的代码在父元素上使用了stopPropagation。子元素会先获取点击事件。这是基于你在子元素li上有一个第二个事件,但并未包含在你的问题中。否则,只有一个父级事件。 - freedomn-m
我为您创建了一段代码片段。请添加您不想执行的函数。 - mplungjan
(注意:第二个事件是通过编辑添加的,需要由OP更新,通过[编辑]进行更新) - freedomn-m
4个回答

3

$('#testUl .innerUl li').on('click', function(e) {
    e.stopPropagation();
});

// or 
$('#testUl li').on('click', function(e) {
    e.stopPropagation();
});

$('#testUl > li').on('click', function(e) {
   alert('test');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- #testUl -->
<ul id="testUl">
    <!-- #testUl > li -->
    <li>
        <!-- #testUl > li > a or #testUl a -->
        <a href="#">Test A</a>
        <!-- #testUl > li > .innerUl or #testUl .innerUl -->
        <div class="innerUl">
            <!-- #testUl > li > .innerUl > ul or #testUl ul -->
            <ul>
                <!-- #testUl > li > .innerUl > ul > li or #testUl li or #testUl .innerUl li or .innerUl li -->
                <li>Inner A</li>
                <li>Inner B</li>
                <li>Inner C</li>
            </ul>
        </div>
    </li>
</ul>

您在使用错误的选择器停止事件传播。
当您使用#testUl > li时,您调用第一个li子元素,但是在#testUl上有li元素内部的li,因此请调用#testUl li#testUl .innerUl li

3

如果没有使用jQuery,你可以使用事件委托并使用Element.closest()来确定操作。

document.addEventListener(`click`, handle);

function handle(evt) {
  console.clear();
  
  if (!evt.target.closest(`.innerUl`) && evt.target.closest(`#testUl`)) {
      console.log(`You clicked (something within) the first li of ul#testUl`);
  }
}
<ul id="testUl">
  <li>
    <a href="#">Test A</a>
    <div class="innerUl">
      <ul>
        <li>Inner A</li>
        <li>Inner B</li>
        <li>Inner C</li>
      </ul>
    </div>
  </li>
</ul>

与jQuery相同的想法

$("#testUl").on("click", evt => {
    console.clear();
    if (!evt.target.closest(`.innerUl`) && evt.target.closest(`#testUl`)) {
      console.log(`You clicked ${evt.target.outerHTML}`);
    }
  });
<script 
  src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js">
</script>

<ul id="testUl">
  <li>
    <a href="#">Test A</a>
    <div class="innerUl">
      <ul>
        <li>Inner A</li>
        <li>Inner B</li>
        <li>Inner C</li>
      </ul>
    </div>
  </li>
</ul>


这个可以正常工作,但是它会在每次页面点击时被调用吗? - naxsi
1
@naxsi 是的,但这并不是真正的问题。如果条件不满足,什么也不会发生。 - KooiInc
第二,委托可能会增加CPU负载,因为容器级别的处理程序对容器中任何地方的事件都会做出反应,无论它们是否与我们有关。但通常负载是可以忽略不计的,所以我们不考虑它。第二个例子(jQuery)只监视ul#testUl上的点击事件。 - KooiInc

2

您可以比较e.target,它是具有click事件的元素,以及e.currentTarget,它是您实际点击的元素。如果它们不匹配,则返回而不执行函数的其余部分。

$('#testUl > li').on('click', (e) => {
    if (e.target !== e.currentTarget) {
        return;
    }
    console.log('parent');
});

$('.innerUl li').on('click', (e) => {
    if (e.target !== e.currentTarget) {
        return;
    }
    console.log('child');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="testUl">
    <li>
        Test A
        <div class="innerUl">
            <ul>
                <li>Inner A</li>
                <li>Inner B</li>
                <li>Inner C</li>
            </ul>
        </div>
    </li>
</ul>


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接