JavaScript,停止preventDefault()事件传递给子元素

4
我有一个div容器,由于某种原因我需要添加e.preventDefault(),但令人惊讶的是它也阻止了锚元素正常工作。

jQuery('#anything').on("click", function(e) {
  e.preventDefault();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="anything">
  <a href="https://google.com"> Link should work </a>
</div>

我没想到锚点不起作用,以前从未遇到过这种情况。我尝试了在某个地方建议的StopPropagation(),但并没有起作用。
我该怎么让锚点重新起作用呢?

你能解释一下为什么要使用preventDefault()吗? - Jagdeesh Kumar
你能详细说明一下这个逻辑的目的吗?除了取消锚点事件之外,我很难理解发生了什么。看起来有更多的事情发生了,而这些事情并没有在你展示的代码中呈现。#anything元素是否有自己的逻辑来取消事件? - rishat
@ri-chan,你的问题是正确的,使用preventDefault()在div上似乎不太明智。我有一个包含多个表单的div,这些表单在用户采取特定操作之前不应该被提交。但是,该div中的链接应该可以正常工作。我认为可能有更好的逻辑,但我也很好奇这个问题。 - nikhil123
不确定为什么要使用 e.preventDefault(); 如果“链接应该工作”。 但是,如果您想防止执行任何父事件处理程序,则应使用 e.stopPropagation(); - Hil
是的,但是e.stopPropagation()应该应用于我们想要避免preventDefault()(在我的情况下是锚点)的子元素,而不是父元素(在我的情况下是div#anything)。这已经在答案中解释过了。 - nikhil123
3个回答

6

一种选择是使用事件委托并排除所有的 a 元素触发监听器:

jQuery('#anything').on("click", '*:not(a)', function(e) {
  e.preventDefault();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="anything">
  <a href="https://google.com"> Link should work </a>
</div>

如果您想确保不会触发#anything子元素内的任何点击事件,则将#anything作为委托选择器放置。这是使用本机JavaScript实现的:

document.querySelector('#anything').addEventListener('click', (e) => {
  console.log('listener running');
  if (!e.target.matches('#anything')) return;
  console.log('prevented default');
  e.preventDefault();
});
  
<a href="www.google.com" id="anything">Parent A<span>Child Span</span></a>

(尽管在只有一个
的情况下使用preventDefault()并没有太多意义..?)

嗨,我刚刚注意到,尽管您的解决方案阻止了preventDefault()传递到锚点元素并应用于所有其他子元素,但是preventDefalut()实际上并不适用于#anything div本身。这就是为什么在您的第二个解决方案中,我尝试了以下内容:jQuery('#anything').on("click", '#anything, *:not(a)', function(e) { e.preventDefault(); });但它仍然无法在#anything div本身上工作。事实上,这个jQuery('#anything').on("click", '#anything', function(e) { e.preventDefault(); });什么也没做。请问您能帮忙吗? - nikhil123
这就是为什么我说“(尽管在只有一个div上使用preventDefault()没有太多意义..?)” - 不清楚你想用preventDefault()做什么,因为如果它只在目标是div时激活,那还有什么意义呢?你能解释一下preventDefault()的作用吗? - CertainPerformance
如果一个div有任何默认操作,那么调用preventDefault会阻止该默认操作触发。例如,如果您将相同的过程应用于a(默认操作:重定向),并且a有一个子span,则您可以看到差异。单击span会重定向,而在a外部单击不会重定向,会触发处理程序。 - CertainPerformance
1
感谢您的耐心等待,请允许我问最后一个问题,拿这个例子 <a href="www.google.com" id="a">Click Alert <span>No Alert </span></a> 我刚刚尝试了这个 JavaScript 代码 jQuery('#a').on("click", '#a', function(e) { alert("hello");}) 您认为这个函数只应该绑定到文本“Click alert”,而不是它的子元素 span,但事实并非如此,单击事件没有绑定到任何元素。 - nikhil123
哦,看来它最终还是不起作用。有趣。我原本以为jQuery的事件委托与本机Javascript中的.matches类似,您可以在此处查看:https://jsfiddle.net/u8z1wtg2/ 但由于某种原因,jQuery的行为不同。它必须仅过滤后代,而不是添加侦听器的基本元素。 - CertainPerformance
显示剩余2条评论

3
在你的子元素上使用 e.stopPropagation(); 方法。

jQuery('#anything').on("click", function(e){
       e.preventDefault();

        });
jQuery('#a1').on("click", function(e){
           e.stopPropagation();
        });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="anything">
    <a href="https://google.com" id="a1"> Link should work </a>
 </div>

   


2
你的解决方案也可以,太棒了,谢谢 :) - nikhil123

2
为了阻止 preventDefault() 传递给所有子元素,您需要在所有子元素上使用 stopPropagation 来处理点击事件。

jQuery('#anything').on("click", function(e){
    e.preventDefault();
 }).children().click(function(e) { // catch all children click
    e.stopPropagation();
 });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="anything">
    <a href="https://google.com"> Link should work </a>
 </div>


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