简体   繁体   English

追加元素并删除它会破坏jquery中的所有事件处理程序?

[英]appending element and removing it destroys all event handlers in jquery?

Ok I create element, assign click handler, and append it to body. 好我创建元素,分配点击处理程序,并将其附加到正文。 Then i remove it and reappend it and click handler is no longer working??? 然后我删除它并重新加载它并单击处理程序不再工作???

Why would this happen. 为什么会这样呢?

var btn = $('<button>').text('hi').click(function(){console.log(3);});
var div = $('<div>');
div.append(btn);
$('body').append(div);
//click it now, it works..
div.html('');
div.append(btn);
// now button doesn't work..

So why is this happening and what can i do to fix it. 那么为什么会发生这种情况,我该怎么做才能解决它。

Since .html('') is essentially the same as .empty() , the following applies (from the jQuery docs ): 由于.html('').empty()基本相同,因此以下适用(来自jQuery文档 ):

To avoid memory leaks, jQuery removes other constructs such as data and event handlers from the child elements before removing the elements themselves. 为了避免内存泄漏,jQuery在删除元素本身之前从子元素中删除了其他构造,如数据和事件处理程序。

If you want to remove elements without destroying their data or event handlers (so they can be re-added later), use .detach() instead. 如果要在不破坏其数据或事件处理程序的情况下删除元素(以便以后可以重新添加),请改用.detach()

One option would be to use event delegation . 一种选择是使用事件委托 In doing so, the event isn't bound directly to the button element, it is bound to a constant parent element that isn't removed. 在这样做时,事件不直接绑定到button元素,它绑定到未删除的常量父元素。

Example Here 这里的例子

$(document).on('click', 'button', function () {
    // ..
});

As mentioned above, another option would be to use the .detach() method in order to remove the element from the DOM, without removing attached event listeners. 如上所述,另一种选择是使用.detach()方法从DOM中删除元素,而不删除附加的事件侦听器。

The .detach() method is the same as .remove() , except that .detach() keeps all jQuery data associated with the removed elements. .detach()方法.remove()相同,除了.detach()保留与删除的元素关联的所有jQuery数据。 This method is useful when removed elements are to be reinserted into the DOM at a later time. 当删除的元素稍后要重新插入DOM时,此方法很有用。

Example Here 这里的例子

div.find('button').detach();
div.append(btn);

put this after the second div.append(btn); 把它放在第二个div.append(btn)之后; - > btn = $('button').text('hi').click(function(){console.log(3);}); - > btn = $('button').text('hi').click(function(){console.log(3);});

It happens because you're calling html() on the DIV that contains the button. 这是因为你在包含按钮的DIV上调用html()

When you call html() with an empty string, it calls empty() internally. 当您使用空字符串调用html()时,它会在内部调用empty()
Calling empty() on an element iterates over all the elements inside that element removing all data and events securely. 在元素上调用empty()会迭代该元素内的所有元素,从而安全地删除所有数据和事件。

It does this by calling jQuery.cleanData on the button, which again explicitly calls jQuery.removeEvent , removing all events on the button. 它通过在按钮上调用jQuery.cleanData来实现这一点,该按钮再次显式调用jQuery.removeEvent ,删除按钮上的所有事件。

The button is still stored in the variable btn , so it can be appended again, but it has lost all data and any events attached to it because the parent element had html("") called on it. 该按钮仍然存储在变量btn ,因此它可以再次附加,但它已丢失所有数据和附加到它的任何事件,因为父元素上调用了html("")

The solution is to use detach() to remove the element with all the data and events intact, so it can be appended again, or you can attach the event to a parent element that isn't removed, or you could just hide the element, generally there's no reason to remove the element just to reappend it, it's better to hide it. 解决方案是使用detach()删除所有数据和事件完整的元素,因此可以再次追加,或者您可以将事件附加到未删除的父元素,或者您可以隐藏元素,通常没有理由删除元素只是为了重新加载它,最好隐藏它。

FIDDLE 小提琴

This is very interesting situation. 这是非常有趣的情况。 What happens when you clear div with html('') method. 使用html('')方法清除div时会发生什么。 Take a look at source code and you will see that internally jQuery calls jQuery.cleanData(getAll(elem, false)); 看看源代码 ,你会看到内部jQuery调用jQuery.cleanData(getAll(elem, false)); . This method is responsible for removing all the related data for all child elements that have already been removed. 此方法负责删除已删除的所有子元素的所有相关data This is important in order to avoid memory leaks. 这对于避免内存泄漏很重要。

Clearing data also removes events bound with on (and similar) methods, because those event handlers are also stored in internal cache object. 清除数据还会删除与on (和类似)方法绑定的事件,因为这些事件处理程序也存储在内部缓存对象中。

So as the result, even though you removed content of the div , the btn object is still in memory, but the event bound to it previously is gone. 因此,即使您删除了div内容, btn对象仍然在内存中,但之前绑定到它的事件已经消失。

This was the explanation of the problem. 这是对问题的解释。 The solution is to use dedicated method called detach . 解决方案是使用称为detach专用方法。 It will remove button from the DOM but will keep event data in case element will later be appended again. 它将从DOM中删除按钮,但会保留事件数据,以便稍后再次附加元素。

// remove element but keep its data
btn.detach();

// append back
div.append(btn);

In situations like this you should not use html('') . 在这种情况下,你不应该使用html('')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM