如何在子元素被点击时防止父元素的onclick事件触发?

12

我有两个onclick事件的问题,它们有些类似,所以我会在这里一起问。

第一个问题:

我在div中有一个复选框。输入框具有一个onchange函数,而div具有一个onclick函数。

<div onclick="doSomething()">
     <input type="checkbox" onchange="doSomethingElse()" />
</div>

当我勾选/取消复选框时,同时触发了doSomething()和doSomethingElse()。有什么想法可以防止这种情况发生吗?我尝试了在onchange="doSomethingElse(event)"中使用,并且在doSomethingElse(e)函数中加入e.stopPropagation();但这并没有起作用。

其次:

我有一个包含图片的div。该div具有onclick函数,但是图片没有。图片故意比div更大,超出了div的范围。

-----------------------
|        image        |
|   ---------------   |
|   |     div     |   |
|   |             |   |
|   ---------------   |
|                     |
-----------------------

我只希望当用户点击

框范围内的区域时才触发onclick事件。但是,如果你点击了溢出到
外部的图像的一部分,onclick事件也会触发... 有什么想法吗?

对我来说,第一个问题比第二个问题更重要。但如果有人能回答两个问题,那就太棒了!

非常感谢您的帮助,
Matt


请将其分为两个帖子。虽然您提出了两个“单击处理”问题,但主题并不能同时解决它们。 - Chadwick
11个回答

8

对于你的第一个问题:IE不支持stopPropagation(),取而代之的是你应该使用e.cancelBubble = true。首先执行一个函数检查,以找出你应该使用哪种方法(if (e.stopPropagation) {code})。

对于你的第二个问题:也许包含一个处理点击事件的第二个div?

<div><img src="image.jpg"/></div>
<div style="position:absolute" onclick="doSomething();"></div>

然后正确地定位第二个div。


5

针对您的第二个问题,当点击事件发生时,您可以获取指针的坐标,并将其与div的坐标进行比较(实际实现取决于您使用哪个js库)。

针对您的第一个问题,要阻止事件冒泡,您必须使用:

event.cancelBubble = true;
if(event.stopPropagation) event.stopPropagation();

3
在您的第一个示例中,复选框位于div内部,onchange事件与onclick事件不同,因此在onchange处理程序中调用event.stopPropagation()将无法阻止外部的onclick事件触发。您需要在复选框上添加另一个onclick处理程序来防止点击向上传播。
<div onclick="doSomething()">
     <input type="checkbox" onclick="event.stopPropagation()" onchange="doSomethingElse()" />
</div>

1

第二个:

另请参阅:

[img onmousedown="if (!clicking) alert('parent clicked') " ...]

[div onmousedown="clicking = true"
     onclick = " alert('child clicked") "
     onmouseup="clicking = false"

1

我有一个与你第一个问题非常相似的问题。但是,不是一个<div>和一个复选框,而是一个表格。看一下我的不工作代码:

<table>
  <tr onClick="alert('I expect this alert when Cell_1 or Cell_2 are clicked but not Cell_3')">
    <td>Cell_1</td>
    <td>Cell_2</td>
    <td onClick="alert('I expect this alert only when Cell_3 is clicked')">Cell_3</td>
  </tr>
<table>

点击Cell_1或Cell_2,我的代码按照预期工作,但是当点击Cell_3时不起作用,因为它显示了2个警报。
第一个警报是:
“只有在点击Cell_3时我才期望看到这个警报”
第二个警报是:
“当点击Cell_1或Cell_2时,我期望看到这个警报,但不包括Cell_3。”
通过谷歌搜索,我找到了这篇精彩的文章,发表在Quirksmode上。
简单来说,我可以通过以下方式解决这个问题:
<table>
  <tr onClick="alert('I expect this alert when Cell_1 or Cell_2 are clicked but not Cell_3')">
    <td>Cell_1</td>
    <td>Cell_2</td>
    <td onClick="Cell_3Alert(event)">Cell_3</td>
  </tr>
<table>

而且Javascript:

function Cell_3Alert(e) {
  alert('I expect this alert only when Cell_3 is clicked');

  if (!e) var e = window.event; 
  e.cancelBubble = true;
  if (e.stopPropagation) e.stopPropagation();
}

我已经测试过,它在FireFox 3.6+、IE6+和Chrome上都可以运行。

希望能有所帮助!


1

0

我遇到了同样的问题。对于我来说,这是侧边栏菜单中的一个 span 标签在另一个 span 标签中。子类别应该在点击时切换打开,但内容被点击时不应该。但是,通过查看“click”事件的属性,我想我找到了解决方案,并编写了以下代码:

function sidebar_click(event)
{
    if (event.target == event.currentTarget)
        event.currentTarget.classList.toggle('open');
}

只有当目标 = 当前目标时才会运行。目标是您单击的项目,当前目标是事件处理程序链接到的项目。如果它们相同,则执行,否则不执行。

希望这可以帮到你。


0
对于第二个问题,您可以将div放在图像前面,而不是将图像标签放在div中。这样应该可以为您提供所需的功能。

图片必须在div中,我已经考虑过这个选项了。谢谢。 - Matt

0

我不确定你的第一个问题是否是一个简化版。如果确实是这样,我会完全将div中的onClick删除。

但我怀疑你的实际情况更加复杂,所以我并不认为这是一个答案。

对于第二种情况,我会将图像分成五个部分,只将其中一个放在div中,如下所示:

+------------------------------------------------------+
|                     Image part 1                     |
+------------------------------------------------------+
| Image part 2 | Image part 3 (and div) | Image part 4 |
+------------------------------------------------------+
|                     Image part 5                     |
+------------------------------------------------------+

我知道这有点笨拙,但我倾向于首先选择最简单的解决方案。


好主意,肯定会起作用。但是我需要保持图像完整。不过还是谢谢! - Matt

0

首先尝试使用e.preventBubble()并从处理程序中返回false。

其次,您可以捕获单击事件并检查事件的目标。如果您使用像jQuery这样规范化事件的库,则最容易使用e.target返回触发事件的确切元素。另一个选项是将单击处理程序放置在图像上方溢出图像的任何容器上。


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