jQuery - 从 DOM 中删除元素时触发事件

发布于 2024-08-20 10:17:50 字数 338 浏览 4 评论 0原文

我试图弄清楚当从页面中删除元素时如何执行一些 js 代码:

jQuery('#some-element').remove(); // remove some element from the page
/* need to figure out how to independently detect the above happened */

是否有为此量身定制的事件,例如:

jQuery('#some-element').onremoval( function() {
    // do post-mortem stuff here
});

I'm trying to figure out how to execute some js code when an element is removed from the page:

jQuery('#some-element').remove(); // remove some element from the page
/* need to figure out how to independently detect the above happened */

is there an event tailored for that, something like:

jQuery('#some-element').onremoval( function() {
    // do post-mortem stuff here
});

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

只是我以为 2024-08-27 10:17:50

为此,您可以使用 jQuery 特殊事件

简单来说,

设置:

(function($){
  $.event.special.destroyed = {
    remove: function(o) {
      if (o.handler) {
        o.handler()
      }
    }
  }
})(jQuery)

用法:

$('.thing').bind('destroyed', function() {
  // do stuff
})

回答 Pierre 和 DesignerGuy 评论的附录:

调用 $('.thing').off('destroyed') 时不触发回调code>,将if条件改为:if (o.handler && o.type !== 'destroyed') { ... }

You can use jQuery special events for this.

In all simplicity,

Setup:

(function($){
  $.event.special.destroyed = {
    remove: function(o) {
      if (o.handler) {
        o.handler()
      }
    }
  }
})(jQuery)

Usage:

$('.thing').bind('destroyed', function() {
  // do stuff
})

Addendum to answer Pierre and DesignerGuy's comments:

To not have the callback fire when calling $('.thing').off('destroyed'), change the if condition to: if (o.handler && o.type !== 'destroyed') { ... }

无戏配角 2024-08-27 10:17:50

刚刚检查,它已经内置在当前版本的 JQuery 中:

jQuery - v1.9.1

jQuery UI - v1.10.2

$("#myDiv").on("remove", function () {
    alert("Element was removed");
})

重要:这是 Jquery UI 脚本的功能(不是 JQuery),因此您必须加载两个脚本(jquery 和 jquery-ui)才能使其工作。这是示例: http://jsfiddle.net/72RTz/

Just checked, it is already built-in in current version of JQuery:

jQuery - v1.9.1

jQuery UI - v1.10.2

$("#myDiv").on("remove", function () {
    alert("Element was removed");
})

Important: This is functionality of Jquery UI script (not JQuery), so you have to load both scripts (jquery and jquery-ui) to make it work. Here is example: http://jsfiddle.net/72RTz/

最偏执的依靠 2024-08-27 10:17:50

您可以绑定到 DOMNodeRemoved 事件(DOM Level 3 WC3 规范的一部分)。

适用于 IE9、最新版本的 Firefox 和 Chrome。

示例:

$(document).bind("DOMNodeRemoved", function(e)
{
    alert("Removed: " + e.target.nodeName);
});

您还可以通过绑定到 DOMNodeInserted 来在插入元素时收到通知

You can bind to the DOMNodeRemoved event (part of DOM Level 3 WC3 spec).

Works in IE9, latest releases of Firefox and Chrome.

Example:

$(document).bind("DOMNodeRemoved", function(e)
{
    alert("Removed: " + e.target.nodeName);
});

You can also get notification when elements are inserting by binding to DOMNodeInserted

老街孤人 2024-08-27 10:17:50

没有用于删除元素的内置事件,但您可以通过假扩展 jQuery 的默认删除方法来创建一个事件。请注意,必须在实际删除回调之前调用该回调以保留引用。

(function() {
    var ev = new $.Event('remove'),
        orig = $.fn.remove;
    $.fn.remove = function() {
        $(this).trigger(ev);
        return orig.apply(this, arguments);
    }
})();

$('#some-element').bind('remove', function() {
    console.log('removed!');
    // do pre-mortem stuff here
    // 'this' is still a reference to the element, before removing it
});

// some other js code here [...]

$('#some-element').remove();

注意:其他发帖者已经概述了此答案的一些问题。

  1. 当通过 html() replace() 或其他 jQuery 方法删除节点时,这将不起作用
  2. 该事件会冒泡
  3. jQuery UI 也会覆盖删除

最优雅的解决方案这个问题似乎是: https://stackoverflow.com/a/10172676/216941

There is no built-in event for removing elements, but you can create one by fake-extending jQuery's default remove method. Note that the callback must be called before actually removing it to keep reference.

(function() {
    var ev = new $.Event('remove'),
        orig = $.fn.remove;
    $.fn.remove = function() {
        $(this).trigger(ev);
        return orig.apply(this, arguments);
    }
})();

$('#some-element').bind('remove', function() {
    console.log('removed!');
    // do pre-mortem stuff here
    // 'this' is still a reference to the element, before removing it
});

// some other js code here [...]

$('#some-element').remove();

Note: some problems with this answer have been outlined by other posters.

  1. This won't work when the node is removed via html() replace() or other jQuery methods
  2. This event bubbles up
  3. jQuery UI overrides remove as well

The most elegant solution to this problem seems to be: https://stackoverflow.com/a/10172676/216941

九命猫 2024-08-27 10:17:50

挂钩 .remove() 并不是处理此问题的最佳方法,因为那里有很多方法可以从页面中删除元素(例如使用 .html().replace() 等)。

为了防止各种内存泄漏的危险,jQuery内部会尝试调用函数 jQuery.cleanData() 对于每个已删除的元素,无论用于删除它的方法如何。

有关更多详细信息,请参阅此答案: javascript 内存泄漏

因此,为了获得最佳结果,您应该挂钩 cleanData 函数,这正是 jquery.event 的功能.destroyed 插件的作用是:

http://v3.javascriptmvc .com/jquery/dist/jquery.event.destroyed.js

Hooking .remove() is not the best way to handle this as there are many ways to remove elements from the page (e.g. by using .html(), .replace(), etc).

In order to prevent various memory leak hazards, internally jQuery will try to call the function jQuery.cleanData() for each removed element regardless of the method used to remove it.

See this answer for more details: javascript memory leaks

So, for best results, you should hook the cleanData function, which is exactly what the jquery.event.destroyed plugin does:

http://v3.javascriptmvc.com/jquery/dist/jquery.event.destroyed.js

叹倦 2024-08-27 10:17:50

仅需要 jQuery(不需要 jQuery UI)

我已从 jQuery UI 框架中提取了此扩展

适用于:empty()html()< /code> 和 remove()

$.cleanData = ( function( orig ) {
    return function( elems ) {
        var events, elem, i;
        for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
            try {

                // Only trigger remove when necessary to save time
                events = $._data( elem, "events" );
                if ( events && events.remove ) {
                    $( elem ).triggerHandler( "remove" );
                }

            // Http://bugs.jquery.com/ticket/8235
            } catch ( e ) {}
        }
        orig( elems );
    };
} )( $.cleanData );

通过此解决方案,您还可以取消绑定事件处理程序。

$("YourElemSelector").off("remove");

尝试一下! - 示例

$.cleanData = (function(orig) {
  return function(elems) {
    var events, elem, i;
    for (i = 0;
      (elem = elems[i]) != null; i++) {
      try {

        // Only trigger remove when necessary to save time
        events = $._data(elem, "events");
        if (events && events.remove) {
          $(elem).triggerHandler("remove");
        }

        // Http://bugs.jquery.com/ticket/8235
      } catch (e) {}
    }
    orig(elems);
  };
})($.cleanData);


$("#DivToBeRemoved").on("remove", function() {
  console.log("div was removed event fired");
});

$("p").on("remove", function() {
  console.log("p was removed event fired");
});

$("span").on("remove", function() {
  console.log("span was removed event fired");
});

// $("span").off("remove");

$("#DivToBeRemoved").on("click", function() {
  console.log("Div was clicked");
});

function RemoveDiv() {
  //       $("#DivToBeRemoved").parent().html("");    
  $("#DivToBeRemoved").remove();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>OnRemove event handler attached to elements `div`, `p` and `span`.</h3>
<div class="container">
  <br>
  <button onclick="RemoveDiv();">Click here to remove div below</button>
  <div id="DivToBeRemoved">
    DIV TO BE REMOVED 
    contains 1 p element 
    which in turn contains a span element
    <p>i am p (within div)
      <br><br><span>i am span (within div)</span></p>
  </div>
</div>

其他 演示 - jsBin

Only jQuery is required (No jQuery UI needed)

(I have extracted this extension from the jQuery UI framework)

Works with: empty() and html() and remove()

$.cleanData = ( function( orig ) {
    return function( elems ) {
        var events, elem, i;
        for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
            try {

                // Only trigger remove when necessary to save time
                events = $._data( elem, "events" );
                if ( events && events.remove ) {
                    $( elem ).triggerHandler( "remove" );
                }

            // Http://bugs.jquery.com/ticket/8235
            } catch ( e ) {}
        }
        orig( elems );
    };
} )( $.cleanData );

With this solution you can also unbind the event handler.

$("YourElemSelector").off("remove");

Try it! - Example

$.cleanData = (function(orig) {
  return function(elems) {
    var events, elem, i;
    for (i = 0;
      (elem = elems[i]) != null; i++) {
      try {

        // Only trigger remove when necessary to save time
        events = $._data(elem, "events");
        if (events && events.remove) {
          $(elem).triggerHandler("remove");
        }

        // Http://bugs.jquery.com/ticket/8235
      } catch (e) {}
    }
    orig(elems);
  };
})($.cleanData);


$("#DivToBeRemoved").on("remove", function() {
  console.log("div was removed event fired");
});

$("p").on("remove", function() {
  console.log("p was removed event fired");
});

$("span").on("remove", function() {
  console.log("span was removed event fired");
});

// $("span").off("remove");

$("#DivToBeRemoved").on("click", function() {
  console.log("Div was clicked");
});

function RemoveDiv() {
  //       $("#DivToBeRemoved").parent().html("");    
  $("#DivToBeRemoved").remove();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>OnRemove event handler attached to elements `div`, `p` and `span`.</h3>
<div class="container">
  <br>
  <button onclick="RemoveDiv();">Click here to remove div below</button>
  <div id="DivToBeRemoved">
    DIV TO BE REMOVED 
    contains 1 p element 
    which in turn contains a span element
    <p>i am p (within div)
      <br><br><span>i am span (within div)</span></p>
  </div>
</div>

Additional Demo - jsBin

勿忘初心 2024-08-27 10:17:50

对于那些使用 jQuery UI 的人来说:

jQuery UI 已经重写了一些 jQuery 方法来实现 remove 事件,该事件不仅在您显式删除给定元素时得到处理,而且在该元素从DOM 通过任何自清洁 jQuery 方法(例如 replacehtml 等)。这基本上允许您将挂钩放入 jQuery“清理”与 DOM 元素关联的事件和数据时触发的相同事件中。

John Resig 表​​示他愿意在未来版本中实现此活动jQuery 核心,但我不确定它目前处于什么位置。

For those who use jQuery UI:

jQuery UI has overridden some of the jQuery methods to implement a remove event that gets handled not only when you explicitly remove the given element, but also if the element gets removed from the DOM by any self-cleaning jQuery methods (e.g. replace, html, etc.). This basically allows you to put a hook into the same events that get fired when jQuery is "cleaning up" the events and data associated with a DOM element.

John Resig has indicated that he's open to the idea of implementing this event in a future version of jQuery core, but I'm not sure where it stands currently.

吐个泡泡 2024-08-27 10:17:50

我无法让这个答案来解除绑定(尽管更新了请参阅此处),但能够找到解决方法它。答案是创建一个“destroy_proxy”特殊事件来触发“destroyed”事件。您将事件侦听器放在“destroyed_proxy”和“destroyed”上,然后当您想要取消绑定时,只需取消绑定“destroyed”事件:

var count = 1;
(function ($) {
    $.event.special.destroyed_proxy = {
        remove: function (o) {
            $(this).trigger('destroyed');
        }
    }
})(jQuery)

$('.remove').on('click', function () {
    $(this).parent().remove();
});

$('li').on('destroyed_proxy destroyed', function () {
    console.log('Element removed');
    if (count > 2) {
        $('li').off('destroyed');
        console.log('unbinded');
    }
    count++;
});

这是一个 小提琴

I couldn't get this answer to work with unbinding (despite the update see here), but was able to figure out a way around it. The answer was to create a 'destroy_proxy' special event that triggered a 'destroyed' event. You put the event listener on both 'destroyed_proxy' and 'destroyed', then when you want to unbind, you just unbind the 'destroyed' event:

var count = 1;
(function ($) {
    $.event.special.destroyed_proxy = {
        remove: function (o) {
            $(this).trigger('destroyed');
        }
    }
})(jQuery)

$('.remove').on('click', function () {
    $(this).parent().remove();
});

$('li').on('destroyed_proxy destroyed', function () {
    console.log('Element removed');
    if (count > 2) {
        $('li').off('destroyed');
        console.log('unbinded');
    }
    count++;
});

Here is a fiddle

梦在深巷 2024-08-27 10:17:50

我喜欢 mtkopone 使用 jQuery 特殊事件的答案,但请注意,它不起作用 a) 当元素被分离而不是被删除时或 b) 当一些旧的非 jquery 库使用innerHTML 来销毁你的元素时

I like mtkopone's answer using jQuery special events, but note that it doesn't work a) when elements are detached instead of removed or b) when some old non-jquery libraries use innerHTML to destroy your elements

夜雨飘雪 2024-08-27 10:17:50

我不确定是否有一个事件句柄,因此您必须保留 DOM 的副本,并在某种轮询循环中与现有 DOM 进行比较 - 这可能非常令人讨厌。 Firebug 确实会这样做 - 如果您检查 HTML 并运行一些 DOM 更改,它会在 Firebug 控制台中以黄色突出显示更改一段时间。

或者,您可以创建一个删除函数...

var removeElements = function(selector) {
    var elems = jQuery(selector);

    // Your code to notify the removal of the element here...
    alert(elems.length + " elements removed");

    jQuery(selector).remove();
};

// Sample usage
removeElements("#some-element");
removeElements("p");
removeElements(".myclass");

I'm not sure there is an event handle for this, so you would have to keep a copy of the DOM and compare to the existing DOM in some kind of polling loop - which could be quite nasty. Firebug does this though - if you inspect the HTML and run some DOM-changes, it highlights the changes in yellow in the Firebug console for a short time.

Alternatively, you could create a remove function...

var removeElements = function(selector) {
    var elems = jQuery(selector);

    // Your code to notify the removal of the element here...
    alert(elems.length + " elements removed");

    jQuery(selector).remove();
};

// Sample usage
removeElements("#some-element");
removeElements("p");
removeElements(".myclass");
可是我不能没有你 2024-08-27 10:17:50

这。

$.each(
  $('#some-element'), 
        function(i, item){
            item.addEventListener('DOMNodeRemovedFromDocument',
                function(e){ console.log('I has been removed'); console.log(e);
                })
         })

This.

$.each(
  $('#some-element'), 
        function(i, item){
            item.addEventListener('DOMNodeRemovedFromDocument',
                function(e){ console.log('I has been removed'); console.log(e);
                })
         })
忘东忘西忘不掉你 2024-08-27 10:17:50

这是创建 jQuery 实时删除侦听器的方法:

$(document).on('DOMNodeRemoved', function(e)
{
  var $element = $(e.target).find('.element');
  if ($element.length)
  {
    // do anything with $element
  }
});

或者:

$(document).on('DOMNodeRemoved', function(e)
{
  $(e.target).find('.element').each(function()
  {
    // do anything with $(this)
  }
});

This is how to create a jQuery live remove listener:

$(document).on('DOMNodeRemoved', function(e)
{
  var $element = $(e.target).find('.element');
  if ($element.length)
  {
    // do anything with $element
  }
});

Or:

$(document).on('DOMNodeRemoved', function(e)
{
  $(e.target).find('.element').each(function()
  {
    // do anything with $(this)
  }
});
但可醉心 2024-08-27 10:17:50

jQuery 中的“删除”事件工作正常,无需添加。使用一个简单的技巧可能比修补 jQuery 更可靠。

只需在要从 DOM 中删除的元素中修改或添加属性即可。因此,您可以触发任何更新函数,该函数将仅忽略要销毁的元素,并使用属性“do_not_count_it”。

假设我们有一个表格,其中的单元格与价格相对应,并且您只需显示最后的价格:
这是删除价格单元格时触发的选择器(我们在表格的每一行都有一个按钮执行此操作,此处未显示)

$('td[validity="count_it"]').on("remove", function () {
    $(this).attr("validity","do_not_count_it");
    update_prices();
});

这是一个函数,用于查找表格中的最后一个价格,而不考虑最后一个价格一个,如果它是被删除的那个。事实上,当触发“remove”事件并调用此函数时,该元素尚未被删除。

function update_prices(){
      var mytable=$("#pricestable");
      var lastpricecell = mytable.find('td[validity="count_it"]').last();
}

最后, update_prices() 函数工作正常,之后 DOM 元素被删除。

The "remove" event from jQuery works fine, without addition. It might be more reliable in time to use a simple trick, instead of patching jQuery.

Just modify or add an attribute in the element you are about to remove from the DOM. Thus, you can trigger any update function, that will just ignore elements on way to be destroyed, with the attribute "do_not_count_it".

Suppose we have a table with cells corresponding to prices, and that you need to show only the last price:
This is the selector to trigger when a price cell is deleted (we have a button in each line of the table doing that, not shown here)

$('td[validity="count_it"]').on("remove", function () {
    $(this).attr("validity","do_not_count_it");
    update_prices();
});

And here is a function that finds the last price in the table, not taking account of the last one, if it was the one that was removed. Indeed, when the "remove" event is triggered, and when this function is called, the element is not removed yet.

function update_prices(){
      var mytable=$("#pricestable");
      var lastpricecell = mytable.find('td[validity="count_it"]').last();
}

In the end, the update_prices() function works fine, and after that, the DOM element is removed.

鸠书 2024-08-27 10:17:50

我们还可以使用 DOMNodeRemoved:

$("#youridwhichremoved").on("DOMNodeRemoved", function () {
// do stuff
})

We can also use DOMNodeRemoved:

$("#youridwhichremoved").on("DOMNodeRemoved", function () {
// do stuff
})
幽梦紫曦~ 2024-08-27 10:17:50

参考@David的回答:

当你想用另一个函数来执行soo时,例如。 html() 就像我的例子一样,不要忘记在新函数中添加 return :

(function() {
    var ev = new $.Event('html'),
        orig = $.fn.html;
    $.fn.html = function() {
        $(this).trigger(ev);
        return orig.apply(this, arguments);
    }
})();

referencing to @David answer:

When You want to do soo with another function, eg. html() like in my case, don't forget to add return in new function:

(function() {
    var ev = new $.Event('html'),
        orig = $.fn.html;
    $.fn.html = function() {
        $(this).trigger(ev);
        return orig.apply(this, arguments);
    }
})();
忆梦 2024-08-27 10:17:50

Adam's 答案的扩展,以防您需要防止默认,这里有一个解决方法:

$(document).on('DOMNodeRemoved', function(e){
        if($(e.target).hasClass('my-elm') && !e.target.hasAttribute('is-clone')){
            let clone = $(e.target).clone();
            $(clone).attr('is-clone', ''); //allows the clone to be removed without triggering the function again

            //you can do stuff to clone here (ex: add a fade animation)

            $(clone).insertAfter(e.target);
            setTimeout(() => {
                //optional remove clone after 1 second
                $(clone).remove();
            }, 1000);
        }
    });

an extension to Adam's answer incase you need to prevend default, here is a work around:

$(document).on('DOMNodeRemoved', function(e){
        if($(e.target).hasClass('my-elm') && !e.target.hasAttribute('is-clone')){
            let clone = $(e.target).clone();
            $(clone).attr('is-clone', ''); //allows the clone to be removed without triggering the function again

            //you can do stuff to clone here (ex: add a fade animation)

            $(clone).insertAfter(e.target);
            setTimeout(() => {
                //optional remove clone after 1 second
                $(clone).remove();
            }, 1000);
        }
    });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文