我需要在删除元素之前取消绑定jquery事件吗?

47

我有一个页面使用了jquery-ui-dialog。每次打开对话框时,页面内容都会通过ajax加载。然后使用jquery的"on()"绑定一些事件。 当对话框关闭时,它将清空其内容。

问题是,在$.empty()之前,我需要解除".ajax-content"上的事件绑定吗?

编辑关注点1. 这种方式是否会降低JS的性能?如果我这样清空数百个节点。

关注点2. 删除元素是否也会从内存中删除事件(或者从jquery的执行/评估链中)?

目前我没有对它们做任何处理。 如果多次打开/关闭对话框而不进行页面刷新,会导致任何问题吗?

代码看起来像这样:

<div id="jquery-dialog" class="container">
  <div class="ajax-content">
    some buttons....
  </div>
</div>

------after each ajax load------------
$(".ajax-content").on("click", ".button", function(event) {
  //handles the click
});

------on dialog close------------
$("#jquery-dialog").empty();

3
什么好问题?我也很关注这个。 - vietean
3个回答

56

嘿,我知道这是一个旧问题,但我认为被接受的答案是误导的。

虽然正确的做法是在原生JS中解绑事件以避免旧浏览器(比如IE)中的内存泄漏,但调用remove()或empty()已经可以为你完成这个工作。

因此,你当前对empty()的调用已经足够了,它不需要在unbind()之前被执行。

根据jQuery文档(http://api.jquery.com/empty/)

为避免内存泄漏,jQuery会先从子元素中删除数据和事件处理程序,再删除元素本身。


1
谢谢您的简明扼要、重点突出和提供文档参考。+1 - greaterKing

1

最好是解绑,但必须。

大多数浏览器可以正确处理并自动移除这些处理程序。

您还可以查看我是否需要删除事件侦听器

更好的处理此问题的方法是使用事件委托。


谢谢提供链接。学到了新知识。 - Reed

-1
Oscar的回答不完整,如果在你的部分视图(通过ajax加载的视图)中使用.on()附加事件,则必须在.empty()之前调用.off()。
请查看以下代码,如果没有调用.off(),则通过标准的.click()处理程序分配的p1.html中的事件在调用.empty()时被删除,但是通过.on()分配的p2.html中的事件不会被删除,并且每次加载部分时都会重新分配。

index.html

<html>
<body>
<script src="ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    <div id='spi' style="padding: 20px; border: 1px solid #666;">
    </div>
    <br/>
    <a href="p1.html" class="spi">Load Partial 1</a> | 
    <a href="p2.html" class="spi">Load Partial 2</a>
    <script type="text/javascript">
    $(document).on('click', 'a.spi' , function(e) {
        e.preventDefault();

        /* 
        !!! IMPORTANT !!!
        If you do not call .off(), 
        events assigned on p2.html via .on()
        are kept and fired one time for each time p2.html was loaded
        */

        $("#spi").off();  


        $("#spi").empty();
        $("#spi").load($(this).attr('href'));
    });
    </script>
</body>
</html>

p1.html

This is the partial 1<br/>
<br/>
<br/>
<a href="javascript:void(0)" id='p1_l1'>Link 1</a>
<br/><br/>
<a href="javascript:void(0)" id='p1_l2'>Link 2</a>
<br/><br/>
<a href="javascript:void(0)" id='p1_l3'>Link 3</a>


<script type="text/javascript">
    $("#p1_l1").click(function(e) {
        e.preventDefault();
        console.debug("P1: p1_l1");
    });
    $("#p1_l2").click(function(e) {
        e.preventDefault();
        console.debug("P1: p1_l2");
    });
</script>

p2.html

This is the partial 2<br/>
<br/>
<br/>
<a href="javascript:void(0)" id='p2_l1'>Link 1</a>
<br/><br/>
<a href="javascript:void(0)" id='p2_l2'>Link 2</a>


<script type="text/javascript">
    $("#spi").on('click', 'a', function(e) {
        e.preventDefault();
        console.debug( 'P2: ' + $(this).attr('id') );
    });
</script>

在p2.html上调用.on()时,事件被附加到'#spi'(而不是内部的'a'元素)。当您稍后使用.empty()清空它时,您将取消绑定附加到'a'元素上的事件,但是'#spi'上的事件仍然存在。我认为,如果您将$("#spi").on('click', 'a', function)重写为$("#spi a").on('click', function),则可以获得所需的效果。 - Oscar

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