当点击图像时,单击事件不会冒泡

5

我有以下标记:

<ul>
    <li class="tgt"><img src="http://placehold.it/48x48" width="48px" height="48px"></li>
    <li class="tgt"><img src="http://placehold.it/48x48" width="48px" height="48px"></li>
    <li class="tgt"><img src="http://placehold.it/48x48" width="48px" height="48px"></li>
</ul>

来自代码编辑器的代码:

$('.tgt').on('click', function (e) {
    if ($(e.target).hasClass('tgt')) {
        $(e.target).addClass('active');
    }
});

我使用jQuery的事件委托向所有.tgt元素附加了一个点击处理程序。出于某种原因,如果我单击图像,则事件不会冒泡到li。相反,事件目标被显示为图像。
这里是一个代码片段: http://jsfiddle.net/CgC4V/ 为什么事件没有冒泡到li.tgt?

1
最好将代码的一些关键部分放在这个页面上,这样即使某人的防火墙不允许访问jsfiddle,他们也可以回答你的问题。 - Lee Meador
你是在点击图片还是在<li>前面的小圆点? - DevlshOne
希望这可以帮到你:http://jsfiddle.net/Palestinian/CgC4V/5/ - Omar
4个回答

10

事件是冒泡的,但您使用 e.target 进行测试的 目标 元素实际上是被单击的元素,如此处所示:http://jsfiddle.net/CgC4V/1/

这就是事件冒泡应该起作用的方式 - 如果事件不冒泡,则不会触发附加到li元素的处理程序。

您可以使用 this 来引用被单击的 li 元素:

$('.tgt').on('click', function (e) {
    $('.active').removeClass('active');
    if ($(this).hasClass('tgt')) {
        $(this).addClass('active');
    }
});

你可能不需要测试元素是否具有tgt类,因为你已经知道它必须是最初具有该类的li元素之一。

Demo: http://jsfiddle.net/CgC4V/3/

对于评论的更新:

"那我应该访问jquery.event.currentTarget吗?如果上下文不是jquery元素怎么办?jQuery.event的哪个属性具有对正确元素的引用?"

是的,event.currentTarget会给你正确的元素。对于你展示的代码,“通常”,event.currentTarget将与this相同,但是如果你执行了某些操作来更改this的值(例如,如果你使用了$.proxy()Function.prototype.bind()),那么event.currentTarget会给你正确的元素。

还要注意,有时event.currentTarget将是与event.target(和未更改this的情况下)相同的元素-在你的例子中,如果你点击li元素的“点”,则目标是li本身。


1
那我是否应该访问 jquery.event.currentTarget 呢? - Adam
@Adam - 你可以直接使用 this - nnnnnn
在上下文不是jQuery元素的情况下,jQuery.event的哪个属性具有对正确元素的引用? - Adam
你觉得这里的代码很复杂吗?http://jsfiddle.net/Palestinian/8U3cX/ - Omar
@Omar - 意思不是难以理解的复杂,而是比解决 OP 的问题所需的更为复杂。当点击事件冒泡时,没有必要直接处理图像上的点击事件。 - nnnnnn
我以为他也想将事件附加到图片上。谢谢 :) - Omar

1
$('img').on('click', function (e) {
    if ($(e.target).parent('li').hasClass('tgt')) {
        $(e.target).parent('li').addClass('active');
    }
});

这将使img成为实际的目标,但仍为整个列表项提供高亮显示。

我正在寻找一种更通用的解决方案,这样如果标签名称发生变化,我就不会依赖于它。 - Adam

1

e指的是事件,但是你想在单击obj时添加类,所以只需将$(e.target)更改为$(this),然后它应该可以工作:

$('.tgt').on('click', function (e) {
    if ($(this).hasClass('tgt')) {
        $(this).addClass('active');
    }
});

1

你应该使用$(this)而不是event.target,因为$(this)始终是<li>本身,而event.target如果图片是接收点击事件的DOM中最深的元素,则会指向该图片。

查看这个演示。

$('.tgt').on('click', function (e) {
    if ($(this).hasClass('tgt')) {
        $(this).addClass('active');
    }
});

编辑以澄清:请考虑下面的结果。

当点击<li>,而不是<img>时:

  • $(this)指向<li>
  • event.target指向<li>

当点击<img>时:

  • $(this)指向<li>
  • event.target指向<img>

这是因为,在所有接收到点击事件的元素中,event.target将总是指向最深层次的元素。然而,$(this)将始终位于<li>上,并将捕获从被点击的<img>冒泡上来的任何事件。


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