jQuery - Bir öğe DOM'dan kaldırıldığında olayı tetikler


211

Bir öğe sayfadan kaldırıldığında bazı js kodu yürütmek nasıl anlamaya çalışıyorum:

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

bunun için özel bir etkinlik var mı, şuna benzer:

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

Teşekkürler.


1
merakla, kaldırılan elemanla ne yapmak isterdiniz?
Natrium

8
Kaldırdığım parçaya bağımsız olarak bağlanan bir elemanım var, bu yüzden o parçayı ortadan kaldırmak için ne zaman gittiğini tespit etmek istiyorum. Her şeyi yeniden tasarlayabilirdim, ancak yukarıdakileri başarmak bana çok zaman kazandıracak (ve kod).
sa125

Yanıtlar:


118

Yeni kontrol edildi, JQuery'nin şu anki sürümünde zaten yerleşik:

jQuery - v1.9.1

jQuery Kullanıcı Arayüzü - v1.10.2

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

Önemli : Bu Jquery UI betiğinin işlevselliğidir ( JQuery değil), bu nedenle çalışması için her iki betiği de (jquery ve jquery-ui) yüklemeniz gerekir. İşte örnek: http://jsfiddle.net/72RTz/


11
Bu çok yardımcı oldu. Tüm kullanıcı arabirimi kitaplığını indirmek istemiyorsanız, bu işlevin jQuery UI'nin "Widget" bileşeni içinde olduğunu öğrendim.
Neil

5
Bu herhangi bir yerde belgelenmiş mi? Ben sadece jQuery UI widget belgelerine baktı ve bunun bir söz bulamadık. Bunun resmi olarak desteklenip desteklenmediğini / kullanımıyla ilgili herhangi bir uyarıyı görmek ister misiniz ...
Josh

Bu işe yaramaz - jQuery 1.10.2'de denendi, ancak mtkopone tarafından aşağıdaki cevap mükemmel çalışıyor, bu nedenle bu sorunun cevabını güncellemek için oy vereceğim
Marcin

20
Bu sadece kısmen çalışıyor. removeEleman üzerinde yaparsanız , ateş eder, ancak eleman başka bir şekilde yok edilirse, üzerine yazılarak söyleyin, işe yaramaz.
Carl Smith

Haklı olabilirsin, muhtemelen bu vaka için başka bir olay adı var. Davanız için jsfiddle örneği sağlayabilirseniz harika olur.
Philipp Munin

195

Bunun için jQuery özel etkinliklerini kullanabilirsiniz .

Tüm basitlikte,

Kurmak:

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

Kullanımı:

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

Pierre ve DesignerGuy'un yorumlarına cevap vermek için Zeyilname:

Arama yaparken geri aramanın $('.thing').off('destroyed')başlatılmaması için if koşulunu şu şekilde değiştirin:if (o.handler && o.type !== 'destroyed') { ... }


15
Gerçekten güzel bir çözüm. Ben Alman daha fazla bilgi için özel etkinlikler hakkında güzel bir yazı var
antti_s 16:12

11
+1, şimdiye kadar bu özel etkinlikleri tamamen kaçırmayı başardı, yararlı ol! Yukarıdakileri henüz uyguladığını belirtmek için bir şey, aksi takdirde olaya o.handler()geçmek en iyisidir o.handler.apply(this,arguments)ve veri nesneleri olay dinleyicisinden geçmez.
Pebbl

6
Ancak, jQuery olmadan öğeleri kaldırdığınızda bu çalışmaz.
djjeck

5
bu işe yaramaz a) elemanlar kaldırılmak yerine ayrıldığında veya b) bazı eski jquery olmayan kütüphaneler öğelerinizi yok etmek için innerHTML kullandığında (djjeck'in söylediklerine benzer)
Charon ME

5
$('.thing').unbind('destroyed')Gerçekten rahatsız edici olabileceği zaman işleyicinin çağrıldığına dikkat edin (çünkü işleyicinin işleyicinin çağrılmasını istemediğimiz anlamına gelir ...)
Pierre

54

DOMNodeRemoved olayına (DOM Level 3 WC3 spesifikasyonunun bir parçası) bağlanabilirsiniz.

IE9'da çalışır, Firefox ve Chrome'un son sürümleri.

Misal:

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

Ayrıca, öğelere ekleme yaparak DOMNodeInserted


13
Not: "Bir dokümana DOM mutasyon dinleyicileri eklemek, söz konusu dokümanda diğer DOM değişikliklerinin performansını büyük ölçüde düşürür (1,5 - 7 kat daha yavaş yapar!). from: developer.mozilla.org/tr/DOM/Mutation_events
Matt Crinklaw-Vogt

1
NodeName benim için nadiren kullanışlı olsa da bunu sevdim. Sadece e.target.classNameveya kullanıyorum if ($(e.target).hasClass('my-class')) { ....
Micah Alcorn

Bu elemanın kendisi üzerinde değil, sadece çocukları üzerinde çalışıyor.
Xdg

Şaşırtıcı cevap! Gerçekten bana yardım etti!
Kir Mazur

Yavaş ve üretimdeki kod için kötü bir fikir olabilir, ancak bu senkronize (MutationObserver'ın aksine) ve herhangi bir düğüm (sadece jQuery ile kaldırılan düğümler için değil ) çalışan tek yöntem gibi görünüyor . Bu hata ayıklama için mükemmel bir seçenektir.
CertainPerformance

38

Öğeleri kaldırmak için yerleşik bir etkinlik yoktur, ancak sahte genişleyen jQuery'nin varsayılan kaldırma yöntemiyle bir etkinlik oluşturabilirsiniz. Referansı tutmak için geri aramanın kaldırılmadan önce çağrılması gerektiğini unutmayın.

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

Not: Bu yanıtla ilgili bazı sorunlar diğer posterler tarafından özetlenmiştir.

  1. Düğüm yoluyla kaldırıldığında bu çalışmaz html() replace() veya diğer jQuery yöntemleri
  2. Bu olay patlıyor
  3. jQuery kullanıcı arayüzü geçersiz kılmaları da geçersiz kılar

Bu sorunun en zarif çözümü şöyledir: https://stackoverflow.com/a/10172676/216941


2
Bunun için teşekkürler! Küçük bir ek: kaldırma olayı patladığı için, bir çocuk çıkarıldığında da alacaksınız, bu yüzden işleyiciyi şu şekilde yazın:$('#some-element').bind('remove', function(ev) { if (ev.target === this) { console.log('removed!'); } });
meyertee

3
Bu benim için kutudan işe yaramadı - sonucu orig.apply'den döndürmek zorunda kaldım.
fturtle

1
Aslında @Adam, öyle, ancak çapraz tarayıcı uyumlu. Meyertee / fturtle'ın eklemeleri ile HTML'yi değiştirmek / boşaltmak yerine yalnızca bu yöntemle öğeleri kaldırdığınız sürece mükemmel bir güvenilir çözümdür. Daha esnek bir şey için, evet DOM mutasyon olayları iyidir, ancak bunlardan şüpheliyim yapısı daha da gelişerek değişmesi muhtemel DOM etkinliklerini değil, bir uygulamadaki iş etkinliklerini dinlemelisiniz. Ayrıca, DOM mutasyon olaylarına abone olmak, programınızın karmaşık DOM hiyerarşilerinde gecikmeye maruz kalabileceği anlamına gelir.
Will Morgan

1
Doğruluk konusundaki tek görüşüm - 'öğeleri kaldırmak için herhangi bir etkinlik yok' --- 3. düzey DOM olaylarını uygulayan tarayıcılar için yerleşik bir etkinlik var (cevabımda ayrıntılı olarak belirtildiği gibi).
Adam

4
Bu, 'kaldır' işlevi kullanılarak kaldırılan öğeleri algılasa da, başka yollarla kaldırılan öğeleri algılayamaz (örn. JQuery'nin html, replace vb. Kullanılarak). Daha eksiksiz bir çözüm için lütfen cevabıma bakın.
zah

32

Çengel .remove(), sayfadan öğeleri kaldırmanın birçok yolu olduğundan (ör..html() ,.replace() vs.).

Çeşitli bellek sızıntısı tehlikelerini önlemek için, dahili olarak jQuery, jQuery.cleanData()kaldırmak için kullanılan yönteme bakılmaksızın, kaldırılan her öğe için işlevi çağırmayı dener .

Daha fazla ayrıntı için bu cevaba bakın: javascript bellek sızıntıları

Bu nedenle, en iyi sonuçlar için, jquery.event.destroyed eklentisinin yaptığı cleanDatatam olarak işlevi kancalamanız gerekir :

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


Bu fikir cleanDatabana çok yardımcı oldu! Çok teşekkür ederim, Joe :)
Petr Vostrel

1
Güzel cevap, ama yine de sadece jQuery yöntemleri için çalışıyor. Altınızdan "halıyı çekip çıkarabilecek" başka bir platformla bütünleşiyorsanız - Adam'ın cevabı en mantıklıdır.
Bron Davies

7

JQuery kullanıcı arayüzünü kullananlar için:

jQuery UI, removeyalnızca belirli bir öğeyi açıkça kaldırdığınızda değil, aynı zamanda öğe DOM'dan herhangi bir kendi kendini temizleyen jQuery yöntemiyle (örn replace. html, vb. . Bu temelde, jQuery bir DOM öğesiyle ilişkili olayları ve verileri "temizlerken" tetiklenen aynı olaylara bir kanca koymanıza izin verir.

John Resig, bu etkinliği jQuery çekirdeğinin gelecekteki bir sürümünde uygulama fikrine açık olduğunu belirtti, ancak şu anda nerede durduğundan emin değilim.


6

Sadece jQuery gereklidir (jQuery kullanıcı arayüzü gerekmez)

( Bu uzantıyı jQuery UI çerçevesinden çıkardım )

Şununla çalışır: empty()ve html()veremove()

$.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 );

Bu çözüm ile de yapabilirsiniz unbind olay işleyicisi.

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

Dene! - Misal

$.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>

Ek Demo - jsBin


4

( Buradaki güncellemeye rağmen) bağlama ile çalışmak için bu cevabı alamadım , ancak bunun etrafında bir yol bulabildim. Cevap, 'yokedilen' bir olayı tetikleyen bir 'destroy_proxy' özel etkinliği oluşturmaktı. Olay dinleyicisini hem 'destroyed_proxy' hem de 'destroyed' üzerine koydunuz, sonra bağlamak istediğinizde, sadece 'destroyed' olayını çözüyorsunuz:

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++;
});

İşte bir keman


Burada tarayıcı uyumluluğu ne olacak? Hala çalışıyor mu?
Vladislav Rastrusny

3

Mtkopone'un jQuery özel etkinliklerini kullanarak yanıtını seviyorum, ancak a) öğelerin kaldırılmak yerine ayrıldığı veya b) bazı eski jquery olmayan kütüphanelerin öğelerinizi yok etmek için innerHTML kullandığını unutmayın.


3
Soruyu açıkça ayırmak için değil .remove () kullanımı istedi çünkü aşağı indirdi. detachöğenin muhtemelen daha sonra yeniden takılması planlandığından, özellikle temizlemeyi tetiklememek için kullanılır. b) hala doğrudur ve en azından DOM mutasyon olayları yaygın olarak uygulandığından henüz güvenilir bir kullanımı yoktur.
Pierre

4
Bahse girerim bunu sadece "eleştirmen" rozeti almak için yaptın;)
Charon ME

1

Bunun için bir olay tanıtıcı olduğundan emin değilim, bu yüzden DOM'un bir kopyasını tutmanız ve bir çeşit yoklama döngüsünde mevcut DOM ile karşılaştırmanız gerekir - ki bu oldukça kötü olabilir. Firebug bunu yapar - HTML'yi inceler ve DOM değişikliklerini çalıştırırsanız, kısa bir süre Firebug konsolundaki sarı değişiklikleri vurgular.

Alternatif olarak, bir kaldırma işlevi oluşturabilirsiniz ...

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");

1
Bu fikir için +1. Yine de, $ ('. İtemToRemove'). CustomRemove (); gibi daha standart bir jQuery çağrısı almak için jQuery'yi (eklenti stili) genişletebilirsiniz. Ayrıca, bir geri çağrıyı parametre olarak kabul etmesi için de yapabilirsiniz.
user113716

1

Nasıl jQuery canlı kaldırma dinleyici oluşturmak için :

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

Veya:

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

1
Bunu yapmakta özgür olmak harika olurdu. Mutasyon olayları kullanımdan kaldırıldığı için ne yazık ki güvenilir değil: developer.mozilla.org/en-US/docs/Web/Guide/Events/…
Kamafeather

1

JQuery "remove" olayı ek olmadan iyi çalışır. JQuery'yi yamalamak yerine basit bir hile kullanmak zaman içinde daha güvenilir olabilir.

DOM'dan kaldırmak üzere olduğunuz öğede bir özelliği değiştirin veya ekleyin. Böylece, "do_not_count_it" özniteliği ile yok edilecek yolda göz ardı edilecek herhangi bir güncelleme işlevini tetikleyebilirsiniz.

Diyelim ki fiyatlara karşılık gelen hücreleri içeren bir tablo var ve sadece son fiyatı göstermeniz gerekiyor: Bu, bir fiyat hücresi silindiğinde tetiklenecek seçicidir (tablonun her satırında bunu gösteren bir düğmemiz var, gösterilmiyor buraya)

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

Ve işte tablodaki son fiyatı bulan, sonuncuyu hesaba katmayan, kaldırılmış olan ise. Aslında, "remove" olayı tetiklendiğinde ve bu işlev çağrıldığında, öğe henüz kaldırılmaz.

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

Sonunda update_prices () işlevi iyi çalışır ve bundan sonra DOM öğesi kaldırılır.


0

@David cevabına referans:

Başka bir işlevle soo yapmak istediğinizde, örn. Benim durumumda olduğu gibi html (), yeni işlevde dönüş eklemeyi unutmayın:

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

0

Bu.

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

1
DOMNodeRemovedFromDocument, Firefox'ta desteklenmiyor gibi görünüyor. Bunun yerine MutationObserver'ı deneyin ?
EricP

0

uzantısıdır Adem'in cevabı burada bir çalışma dönünce, PREVEND varsayılan gerekir örtmek:

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

0

DOMNodeRemoved'i de kullanabiliriz:

$("#youridwhichremoved").on("DOMNodeRemoved", function () {
// do stuff
})
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.