foo函数被调用两次

时间:2014-07-26 15:11:05

标签: javascript jquery

当用户点击可用的div时,我正在克隆div标签。克隆后,我点击div标签后插入它。这个新的div标签也有交叉链接来删除它。但是,当我点击交叉链接时,它会删除该特定div。这意味着它正在发挥作用。现在我还有一个名为foo的函数。添加和删​​除div标签时调用此方法。但是当我点击删除链接时,这个foo函数被调用两次。我知道它的原因是因为我将click事件附加到删除链接的父节点并删除链接本身,因此它被调用两次。但是如何在添加和删除div元素时调用它一次?

这是我的JSFIDDLE

HTML:

<div class="container">
    <div class="bx"></div>    
</div>

这是js

$('body').on('click', '.bx', function (e) {
        var clone = $(this).clone();
        clone.append('<a class="bx-del" href="#">X</a>');
        $(this).after(clone);
        foo();
});



$('body').on('click', '.bx-del', function (e) {
        e.preventDefault();
        $(this).parent().remove();
        foo();
});

function foo() {
    console.log('foo');
}

3 个答案:

答案 0 :(得分:2)

我原来的回答是:

假设.bx-del位于.bx内(最好在问题中添加html),那么在e.stopPropagation()回调中添加.bx-del应该有效。

E.g。

$('body').on('click', '.bx-del', function (e) {
    e.preventDefault();
    e.stopPropagation();
    $(this).parent().remove();
    foo();
});

Documention here

有人指出,这两个事件实际上都附加在身体上并作为委托事件运行。这个解决方案似乎有效,但问题是它是否可靠。这里的问题是委托事件的运行顺序是什么?他们总是跑步&#34;深度第一&#34;或根据他们被添加的顺序或什么?在我看来,首先运行它们是最合乎逻辑的,但性能方面的考虑也将在这里发挥重要作用。

我一直无法找到任何有关此问题的硬文档。 jQuery .on() documentation

  

jQuery将事件从事件目标起泡到元素所在的位置   处理程序附加(即最里面到最外面的元素)和   为该路径上匹配的所有元素运行处理程序   选择器。

可以解释为,但也可以解释授权概念。

因此,在我看来,对原始问题更安全的解决方案是将两个舔事件合并为一个:

$('body').on('click', '.bx', function (e) {
    var t = $(e.target);
    if( t.hasClass('bx-del') || t.closest('.bx-del').length > 0){
        e.preventDefault();
        t.closest('.bx').remove();
        foo();
    } else {
        var clone = $(this).clone();
        if( $('.bx-del', clone).length == 0 ){
            clone.append('<a class="bx-del" href="#">X</a>');
        }
        $(this).after(clone);
        foo();
    }
});

(我还修复了这样,用删除按钮克隆div并不会添加第二个删除按钮。)

答案 1 :(得分:1)

这是(docs)的event.stopPropagation()。它可以防止事件冒泡进入DOM树。如果您将e.stopPropagation()添加到删除链接点击处理程序,它将不会冒泡到包含它的div并在那里触发点击处理程序:

正如评论中指出的那样,这是不正确的,即使它似乎正常工作。两个事件处理程序都附加到正文,并且只能通过“诡计”来实现。运行特定元素。该事件已经在body元素中,因此不会再冒泡。此外,event.stopPropagation()不应该阻止其他处理程序执行,尽管它们现在无论如何都会这样做。这里使用的正确函数是event.stopImmediatePropagation()docs at jquery)。

$('body').on('click', '.bx-del', function (e) {
        e.preventDefault();
        e.stopImmediatePropagation();
        $(this).parent().remove();
        foo();
});

答案 2 :(得分:0)

因为当事件已经传播到<body>标记并且您的事件都在<body>标记上时,您无法停止传播到<body>标记,我建议您只删除删除事件处理程序直接删除X对象,不使用该事件处理程序的传播。然后,您可以停止该点击的播放,这样父母就不会看到它。在你的情况下,这很容易。

工作演示:http://jsfiddle.net/jfriend00/7CDNG/

$('body').on('click', '.bx', function (e) {
        var clone = $(this).clone();
        clone.append('<a class="bx-del" href="#">X</a>');
        $(this).after(clone);
        clone.find('.bx-del').on('click', function(e) {
            $(this).parent().remove();
            foo();
            // stop propagation and prevent default
            return false;
        })
        foo();
    });

function foo() {
    console.log('foo');
}

或者,您可以将.bx处理程序放在document对象上,将.bx-del处理程序放在body对象上,然后就可以停止传播到{{1来自document处理程序的对象。但是,在这种情况下,将删除事件直接附加到删除对象并且不使用委托事件处理以避免对.bx-del事件的任何可能的错误解释更为清晰。

显然,其他答案在一个click事件处理程序上使用.stopPropagation()以阻止其他事件被触发。这是来自body的jQuery文档的引用:“我认为你很幸运。这是直接从jQuery文档中获取stopPropagation():”请注意,这不会阻止其他处理程序运行中的元素。“由于这两个事件处理程序都在.stopPropagation()对象上,因此使用body来阻止另一个运行时,这似乎不是一个明智和安全的举动。这是我的看法该技术不安全,并不是解决这个问题的概念上正确的方法。