jQuery-요소가 DOM에서 제거 될 때 이벤트 트리거


211

요소가 페이지에서 제거 될 때 일부 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
});

감사.


1
호기심에서 제거 된 요소와 어떤 관계가 있습니까?
Natrium

8
제거하는 조각에 독립적으로 부착되는 요소가 있으므로 해당 요소를 제거하기 위해 해당 조각이 언제 사라 졌는지 감지하고 싶습니다. 모든 것을 다시 디자인 할 수는 있지만 위의 작업을 수행하면 많은 시간과 코드가 절약됩니다.
sa125

답변:


118

방금 확인한 결과 현재 버전의 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/


11
이것은 매우 도움이되었습니다. 전체 UI 라이브러리를 다운로드하지 않으려는 경우이 기능이 jQuery UI의 "Widget"구성 요소 내에 있음을 알게되었습니다.
Neil

5
이것은 어디에나 문서화되어 있습니까? 방금 jQuery UI 위젯 설명서를 살펴본 결과 이에 대한 언급을 찾을 수 없었습니다. 이것이 공식적으로 지원되는지 / 사용에 관한 경고가 있는지 확인하고 싶습니다 ...
josh

작동하지 않는이 한 - jQuery를 1.10.2에 시도 @mtkopone가 완벽하게 작동 아래 그러나 대답은 그러므로 나는 그 질문에 대한 답을 업데이트하기위한 투표 것이다
마르신

20
이것은 부분적으로 만 작동합니다. remove요소 를 수행 하면 요소가 발생하지만 요소가 다른 방법으로 파괴되면 덮어 쓰면 작동하지 않습니다.
Carl Smith

아마이 사건에 대한 다른 이벤트 이름이있을 수 있습니다. 귀하의 사례에 jsfiddle 샘플을 제공 할 수 있다면 좋을 것입니다.
Philipp Munin

195

이를 위해 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')if 조건을 다음과 같이 변경하십시오.if (o.handler && o.type !== 'destroyed') { ... }


15
정말 좋은 해결책입니다. 벤 독일어가 추가 정보를 원하시면 특별 행사에 대한 좋은 작성자가 있습니다 benalman.com/news/2010/03/jquery-special-events을
antti_s

11
+1은 (는) 지금까지이 특별한 이벤트를 완전히 놓쳤습니다. 위에서 방금 구현 한 한 가지 사실은 그렇지 않으면 이벤트 로 변경 o.handler()하는 것이 가장 좋으며 o.handler.apply(this,arguments)데이터 객체는 이벤트 리스너를 통해 전달되지 않습니다.
Pebbl

6
그러나 jQuery없이 요소를 제거하면 작동하지 않습니다.
djjeck

5
a) 요소가 제거되지 않고 분리 될 때 또는 b) 오래된 비 jquery 라이브러리가 innerHTML을 사용하여 요소를 파괴 할 때 (djjeck의 말과 유사)
Charon ME

5
$('.thing').unbind('destroyed')정말 성 가실 수있는 핸들러가 호출 될 때주의하십시오 (바인드 해제는 핸들러가 호출되는 것을 원하지 않기 때문에 ...)
Pierre

54

DOMNodeRemoved 이벤트 (DOM 레벨 3 WC3 스펙의 일부)에 바인딩 할 수 있습니다.

Firefox 및 Chrome의 최신 릴리스 인 IE9에서 작동합니다.

예:

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

바인딩 할 때 요소를 삽입 할 때 알림을받을 수도 있습니다. DOMNodeInserted


13
참고 : "문서에 DOM 변이 리스너를 추가하면 해당 문서에 대한 추가 DOM 수정 성능이 크게 저하됩니다 (1.5-7 배 느리게 만듭니다!"). from : developer.mozilla.org/en/DOM/Mutation_events
Matt Crinklaw-Vogt

1
nodeName이 거의 유용하지는 않지만 이것을 좋아하십시오. 난 그냥 e.target.className또는을 사용 if ($(e.target).hasClass('my-class')) { ...합니다.
Micah Alcorn

이것은 요소 자체가 아니라 하위 요소에서만 작동합니다.
Xdg

놀라운 답변! 정말 도와주었습니다!
Kir Mazur

느리거나 프로덕션 환경에서 코드에 대한 나쁜 생각 일 수 있지만 이것은 MutationObserver와 달리 동 기적으로 작동하는 유일한 방법 과 모든 노드 (jQuery를 통해 제거 된 노드뿐만 아니라 ) 처럼 보입니다 . 이것은 디버깅을위한 훌륭한 옵션입니다.
특정 성능

38

요소를 제거하는 기본 제공 이벤트는 없지만 가짜 확장 jQuery의 기본 remove 메소드를 사용하여 작성할 수 있습니다. 참조를 유지하려면 실제로 제거하기 전에 콜백을 호출해야합니다.

(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도 remove를 재정의합니다.

이 문제에 대한 가장 우아한 해결책은 다음과 같습니다. https://stackoverflow.com/a/10172676/216941


2
고마워요! 한 가지 작은 추가 사항 : 제거 이벤트가 발생하기 때문에 자식이 제거 될 때도이를 수신하므로 처리기를 다음과 같이 작성하십시오.$('#some-element').bind('remove', function(ev) { if (ev.target === this) { console.log('removed!'); } });
meyertee

3
이것은 나를 위해 즉시 작동하지 않았습니다. 나는 orig.apply에서 결과를 반환해야했습니다.
fturtle

1
실제로 @Adam은 크로스 브라우저와 호환됩니다. meyertee / fturtle의 추가 기능을 사용하면 HTML 등을 수정하거나 비우지 않고이 방법으로 요소를 제거하는 한 완벽하게 신뢰할 수있는 솔루션입니다. 유연한 무언가를 위해 DOM 돌연변이 이벤트는 괜찮지 만 나는 회의 론적이었습니다. 추가 개발로 구조가 변경 될 수있는 DOM 이벤트가 아닌 앱에서 비즈니스 이벤트를 수신해야합니다. 또한 DOM 변이 이벤트를 구독하면 프로그램이 복잡한 DOM 계층에서 지연 될 가능성이 있습니다.
Will Morgan

1
정확성에 대한 유일한 의견은 '요소를 제거하기위한 내장 이벤트가 없습니다'라는 문장입니다.
Adam

4
이것은 '제거'기능을 사용하여 제거 된 요소를 감지하지만 다른 방법으로 제거 된 요소를 감지하지 못합니다 (예 : jQuery의 html, replace 등 사용). 더 완벽한 솔루션에 대한 내 대답을 참조하십시오.
zah

32

후킹 .remove()페이지에서 요소를 제거하는 방법에는 여러 가지가 (예를 들어, 사용하여 있기 때문에이 문제를 처리하는 가장 좋은 방법이 아니다 .html(), .replace()등).

내부적으로 다양한 메모리 누수 위험을 방지하기 위해 내부적으로 jQuery는 jQuery.cleanData()제거하는 데 사용 된 메소드에 관계없이 제거 된 각 요소에 대해 함수를 호출하려고 시도 합니다.

자세한 내용은이 답변을 참조하십시오 : javascript memory leaks

따라서 최상의 결과를 얻으 cleanData려면 jquery.event.destroyed 플러그인이 수행 하는 기능과 정확히 일치 하는 함수를 연결해야합니다 .

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


이 통찰력은 cleanData저에게 매우 도움이되었습니다! 대단히 감사합니다, Joe :)
Petr Vostrel

1
좋은 대답이지만 여전히 jQuery 메소드에서만 작동합니다. 아담의 대답이 가장 합리적입니다.
브론 데이비스

7

jQuery UI를 사용하는 사람들 :

jQuery를 UI가 구현하는 jQuery를 방법의 일부를 무시하고있다 remove명시 적으로 지정된 요소를 제거 할뿐만 아니라, 경우 요소가있는 자동 세척의 jQuery 방법으로 DOM에서 (예를 들어, 제거 도착하지 않을 경우에만 처리됩니다 이벤트 replace, html등) . 이것은 기본적으로 jQuery가 DOM 요소와 관련된 이벤트와 데이터를 "정리"할 때 발생하는 동일한 이벤트에 후크를 넣을 수있게합니다.

John Resig는 향후 jQuery 코어 버전에서이 이벤트를 구현하려는 아이디어에 대해 공개하고 있지만 현재 어디에 있는지 잘 모르겠습니다.


6

jQuery 만 필요 (jQuery UI 필요 없음)

( jQuery UI 프레임 워크에서이 확장을 추출했습니다 )

함께 작동 : 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


4

바인딩을 사용 하여이 답변 을 얻을 수는 없었지만 ( 업데이트 는 여기 참조 ), 해결 방법을 찾을 수있었습니다. 답은 '파기'이벤트를 트리거 한 'destroy_proxy'특수 이벤트를 작성하는 것이 었습니다. 이벤트 리스너를 'destroyed_proxy'와 '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++;
});

여기는 바이올린입니다


브라우저 호환성은 어떻습니까? 여전히 작동합니까?
Vladislav Rastrusny

3

jQuery 특수 이벤트를 사용하는 mtkopone의 답변이 마음에 들지만 a) 요소가 제거되지 않고 분리 될 때 또는 b) 오래된 비 jquery 라이브러리가 innerHTML을 사용하여 요소를 파괴 할 때 작동하지 않습니다.


3
질문이 분리되지 않고 .remove () 사용을 명시 적으로 요청했기 때문에 하향 투표했습니다. detach요소는 나중에 다시 연결될 예정이므로 특히 정리를 트리거하지 않는 데 사용됩니다. b) DOM 돌연변이 이벤트가 광범위하게 구현되기 때문에 여전히 사실이며 신뢰할만한 취급이 없다.
Pierre

4
) 나는 당신이 바로 "비평가"뱃지를받을 짓 내기
카론 ME

1

이에 대한 이벤트 핸들이 확실하지 않으므로 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");

1
이 아이디어에 +1 $ ( '. itemToRemove'). customRemove ();와 같은 표준 jQuery 호출을 얻기 위해 jQuery (플러그인 스타일)를 확장 할 수도 있습니다. 콜백을 매개 변수로 허용하도록 만들 수도 있습니다.
user113716

1

다음은 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)
  }
});

1
그렇게하는 것이 자유로울 것입니다. 불행하게도 돌연변이 사건이 더 이상 사용되지 않으므로 신뢰할 수 없다 : developer.mozilla.org/en-US/docs/Web/Guide/Events/…
Kamafeather

1

jQuery의 "remove"이벤트는 추가하지 않고도 정상적으로 작동합니다. 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 요소가 제거됩니다.


0

@David 답변 참조 :

예를 들어 다른 기능으로 진정하고 싶을 때. 내 경우와 같이 html ()은 새로운 함수에 return을 추가하는 것을 잊지 마십시오.

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

0

이.

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

1
Firefox에서 DOMNodeRemovedFromDocument가 지원되지 않는 것 같습니다. 아마도 MutationObserver 를 사용해보십시오 .
EricP

0

불이행을 예방해야 할 경우를 대비 한 Adam의 답변 확장 은 다음과 같습니다.

$(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를 사용할 수도 있습니다.

$("#youridwhichremoved").on("DOMNodeRemoved", function () {
// do stuff
})
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.