使用:not()选择器时,jQuery .on('click')事件会多次触发问题。

3

早上好,

我在页面上有一组盒子,这些盒子呈列表形式呈现,在这些盒子中可能有一些可以单击的链接。 我希望盒子内的链接像正常工作一样(即向上冒泡并执行默认操作,或由 DOM 上进一步的事件处理程序处理),但是如果在其他位置单击该盒子,则应由附加到包含所有盒子的“列表”的特定事件处理程序捕获。

简单的HTML表示:

<div class="boxlist">
    <div class="box" data-boxid="1">
        Some text, and possibly a <a href="#">link</a> and another <a href="#">link</a>, and perhaps even a third <a href="#">link</a>.
    </div>
    <div class="box" data-boxid="2">
        Some more text, this time without a link.
    </div>
</div>

我认为应该可以工作的javascript代码。
$(function () {
    $('.boxlist').on('click', '.box :not(a)', function (e) {
        var boxid= $(this).closest('.box').data('boxid');
        console.log('open: ' + boxid);
    });
});

我原本期望上述的javascript代码可以处理所有非标签的点击事件。然而,出现了这样的问题:当点击方框(无论是方框本身还是其中一个标签)时,它会触发事件X次,其中X是方框列表中所有标签的总数。

所以我有两个问题: 1. 我在使用:not()选择器时做错了什么? 2. 有没有更好的方法来处理这种情况?

谢谢您的帮助!


通过你展示的代码,作为'.box'的唯一后代是'a'元素,事件处理程序将永远不会被调用。但是,即使您添加其他子元素,假设它们没有嵌套,似乎也没有理由让您所说的内容出现。你能构建一个fiddle(例如http://jsbin.com)吗? - Denys Séguret
@Jai 这似乎不是目标。 - Denys Séguret
@dystroy,现在我明白了,我同意你的观点。 - Jai
请查看事件目标。确定是哪个标签被点击了,box还是 a本身,并执行相应动作。这样你就不需要使用:not选择器了。 - SachinGutte
@dystroy 制作了 jsbin,并为其添加了一些结构(实际情况并不是这么简单的框)。然而,在 jsbin 示例中,它不会触发多次。但当点击框本身时,它也不会触发。 - Miika L.
显示剩余3条评论
2个回答

3
使用jQuery的:not选择器实际上非常慢,例如:http://jsperf.com/not-vs-notdasdsad/4,使用事件委托会更好。所以在这种情况下,您需要跟踪.boxlist上的每次单击,但是检查节点类型以查看它是否为锚点。以下是一个示例。
$(function () {
    $('.boxlist').on('click', function(ev){
        if(ev.target.tagName != "A"){
            // handle box click code
            console.log('box click');
            return false;
        }
        // Otherwise allow event to bubble through.
    });
});

这里有一个 jsfiddle 的例子:http://jsfiddle.net/drXmA/

此外,你的代码之所以不起作用,可能有几个原因:

.box :not(a)

应该是

.box:not(a)

这种方法行不通的原因是,.box不是锚点标签,它有一些子元素是锚点标签。如果有一个锚点标签名为.box,它永远也找不到,回调函数也不会执行。将.box更改为锚点标签会导致代码不执行,因为.box是一个锚点标签,而且只能在.box:not(a)运行时才会执行。

这并没有解释清楚 OP 遇到的处理程序多次触发的问题。 - Denys Séguret
1
我甚至无法让他的示例正常工作,以便看到它被多次触发。他发布的内容在 jsfiddle 上对我来说没有任何作用。 - Josh Bedo
是的,对我来说也一样(请参见问题下面的评论),这就是为什么我没有发布替代方案的原因。我并不是说你的答案不好,它可能是解决OP问题的一个方案,我只是说它最多只能算是半个答案。 - Denys Séguret
@dystroy 我似乎也无法在jsbin中重现多个事件问题。盒子的实际内容是一个复杂的结构,而不是简单的文本,它是通过ajax加载的(因此在绑定时存在的列表上附加了点击事件)。然而,这个答案可能会给我提供我需要前进的解决方案。 - Miika L.
所以接受它吧。你可能要么有嵌套的 .box 的问题,要么执行了绑定指令多次。 - Denys Séguret
我对你的答案提出了一个小修改建议,以便它完全符合我的标准,现在我将接受它作为回答核心问题。多个事件将保持神秘状态,除非我能够以某种方式重现它。 - Miika L.

0

我猜你想要这样的东西:

$('.boxlist').on('click', '.box:not(a)', function (e) {
   var boxid = $(this).closest('.box').data('boxid');
   console.log('open: ' + boxid);
}).on('click', '.box a', function (e) {
   e.preventDefault().stopPropagation();
});

演示 FIDDLE

我认为最好停止默认行为,并阻止事件冒泡到其父级。使用.on()链接到.box项目,但不包括<a>,并使用e.preventDefault().stopPropagation();来停止默认行为和事件冒泡。


不,我特意不想在a标签上停止传播,因为我希望它们能冒泡到框外并在其他地方处理。 - Miika L.

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