jQuery-событие триггера при удалении элемента из DOM


Я пытаюсь выяснить, как выполнить некоторые 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
});

спасибо.

14 190

14 ответов:

только что проверено, он уже встроен в текущую версию JQuery:

jQuery-v1.9. 1

jQuery UI-v1.10. 2

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

важно: это функциональность jQuery UI script (не JQuery), поэтому вам нужно загрузить оба скрипта (jquery и jQuery-ui), чтобы заставить его работать. Вот пример: http://jsfiddle.net/72RTz/

можно использовать специальные события jQuery для этого.

во всей простоте,

настройка:

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

использование:

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

добавление к ответу на комментарии Пьера и DesignerGuy:

чтобы не иметь обратного вызова огня при вызове $('.thing').off('destroyed'), измените условие if на:if (o.handler && o.type !== 'destroyed') { ... }

вы можете привязать к событию DOMNodeRemoved (часть спецификации DOM Level 3 WC3).

работает в IE9, последних версиях Firefox и Chrome.

пример:

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

вы также можете получить уведомление, когда элементы вставляются путем привязки к DOMNodeInserted

нет встроенного события для удаления элементов, но вы можете создать его с помощью метода удаления по умолчанию для поддельного расширения 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

подключение .remove() это не лучший способ справиться с этим, так как есть много способов удалить элементы со страницы (например, с помощью .html(),.replace() и т. д.).

чтобы предотвратить различные опасности утечки памяти, внутренне jQuery попытается вызвать функцию jQuery.cleanData() для каждого удаленного элемента независимо от метода, используемого, чтобы удалить его.

посмотреть этот ответ для более подробной информации: утечки памяти javascript

поэтому, для достижения наилучших результатов, вы должны подключить cleanData функция, которая является именно то, что jquery.событие.уничтожен плагин делает:

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

для тех, кто использует jQuery UI:

jQuery UI переопределил некоторые методы jQuery для реализации remove событие, которое обрабатывается не только при явном удалении данного элемента, но и при удалении элемента из DOM любыми самоочищающимися методами jQuery (например,replace,html и т. д.). Это в основном позволяет вам вставлять крючок в те же события, которые запускаются, когда jQuery "очищает" события и данные, связанные с DOM элемент.

Джон в отставку указал что он открыт для идеи реализации этого события в будущей версии ядра jQuery, но я не уверен, где он находится в настоящее время.

Я не мог получить ответ для работы с unbinding (несмотря на обновление посмотреть здесь), но смог найти способ обойти его. Ответ был для создания destroy_proxy' особое событие, которое вызвало "разрушается" событие. Вы ставите прослушиватель событий на '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++;
});

здесь скрипка

решение без использования jQuery UI

(я извлек это расширение из jQuery UI framework)

работает: empty() и html() и 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

Мне нравится ответ mtkopone с использованием специальных событий jQuery, но обратите внимание, что он не работает a) когда элементы отсоединяются вместо удаления или b) когда некоторые старые библиотеки не jquery используют innerHTML для уничтожения ваших элементов

Я не уверен, что для этого есть дескриптор события, поэтому вам нужно будет сохранить копию 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");

Это как создать jQuery live remove listener:

$(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)
  }
});

ссылка на @David ответ:

когда вы хотите сделать soo с другой функцией, например. html () как и в моем случае, не забудьте добавить return в новую функцию:

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

этого.

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

событие "удалить" из jQuery работает нормально, без добавления. Это может быть более надежным во времени, чтобы использовать простой трюк, вместо исправления jQuery.

просто измените или добавьте атрибут в элемент, который вы собираетесь удалить из DOM. Таким образом, вы можете вызвать любую функцию обновления, которая будет просто игнорировать элементы на пути к уничтожению, с атрибутом "do_not_count_it".

предположим, что у нас есть таблица с ячейками, соответствующими ценам, и что вам нужно показать только последняя цена: Это селектор для запуска при удалении ячейки цены (у нас есть кнопка в каждой строке таблицы, которая не показана здесь)

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

а вот функция, которая находит последнюю цену в таблице, не принимая во внимание последнюю, если она была удалена. Действительно, когда запускается событие "удалить", и когда эта функция вызывается, элемент еще не удален.

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

в конце концов, функция update_prices() работает нормально, и после этого элемент DOM удаляется.