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の「ウィジェット」コンポーネント内にこの機能があることを学びました。
Neil

5
これはどこかに文書化されていますか?私はjQuery UIウィジェットのドキュメントを調べただけで、これについての言及は見つかりませんでした。これが正式にサポートされているかどうかを確認したい/それを使用する際の注意事項...
josh

これは機能しません-jQuery 1.10.2で試してみましたが、@ mtkoponeによる以下の回答は完全に機能するため、その質問の回答の更新に投票します
Marcin

20
これは部分的にしか機能しません。remove要素に対して実行すると要素が起動しますが、要素が他の方法で破壊された場合、上書きされて言うと、要素は機能しません。
カールスミス

あなたは正しいかもしれません、おそらくこのケースには他のイベント名があります。あなたのケースに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
本当に素晴らしい解決策。Ben Almanは、詳細について特別イベントに関するすばらしい記事を公開しています:benalman.com/news/2010/03/jquery-special-events
antti_s

11
+1はこれまでこれらの特別なイベントを完全に見逃していたので便利です。上記を実装した直後に述べることの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 2017年

運用中のコードにとっては遅く、悪い考えかもしれませんが、これは同期して(MutationObserverとは異なり)機能する唯一のメソッドのように見えます(jQueryで削除されたノードだけでなく)。これはデバッグに最適なオプションです。
特定のパフォーマンス

37

要素を削除するための組み込みイベントはありませんが、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オーバーライドも削除

この問題の最もエレガントな解決策は次のようです:https : //stackoverflow.com/a/10172676/216941


2
それをありがとう!1つの小さな追加:remove-eventがバブルアップするため、子が削除されたときにもそれを受け取るので、ハンドラーをそのように記述してください:$('#some-element').bind('remove', function(ev) { if (ev.target === this) { console.log('removed!'); } });
meyertee

3
これはそのままでは機能しませんでした。orig.applyから結果を返す必要がありました。
カメ

1
実際、@ Adamはそうですが、クロスブラウザー互換です。meyertee / fturtleの追加により、HTMLを変更/空にするのではなく、このメソッドで要素を削除するだけである限り、これは完全に信頼できるソリューションです。今後の開発で構造が変化する可能性があるDOMのイベントではなく、アプリでビジネスイベントをリッスンする必要があります。また、DOMミューテーションイベントをサブスクライブすることは、プログラムが複雑なDOM階層で遅れる可能性があることを意味します。
Will Morgan

1
正確さについての私の唯一の意見は、「要素を削除するための組み込みイベントはありません」というステートメントです---レベル3のDOMイベントを実装するブラウザー用の組み込みイベントがあります(私の回答で詳述)。
アダム

4
これは 'remove'関数を使用して削除された要素を検出しますが、他の手段(jQueryのhtml、replaceなどを使用)によって削除された要素の検出は失敗します。より完全な解決策については、私の回答を参照してください。
zah

32

フッキング .remove()ページから要素を削除するには多くの方法があるため(例えば、、などを使用して.html().replace()、はこれを処理するための最良の方法ではありません。

さまざまなメモリリークの危険を防ぐために、jQueryはjQuery.cleanData()、削除に使用されたメソッドに関係なく、削除された各要素に対して関数を呼び出そうとします。

詳細については、この回答を参照してください:javascriptのメモリリーク

したがって、最良の結果を得るには、 cleanData関数ます。これは、jquery.event.destroyedプラグインが行うこととまったく同じです。

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


この洞察cleanDataは私にとって非常に役に立ちました!、非常に多くのジョー:)ありがとう
ペトルVostrel

1
いい答えですが、それでもjQueryメソッドでのみ機能します。あなたがあなたの下から「敷物を引き出す」ことができる別のプラットフォームと統合しているなら-アダムの答えは最も理にかなっています。
Bron Davies

7

jQuery UIを使用する人のために:

jQueryのUIは、実装するjQueryのメソッドの一部をオーバーライドしているremoveあなたは、明示的に指定された要素を削除するときだけでなく、扱います、イベントをするだけでなく、要素は、任意のセルフクリーニングjQueryの方法(例えばによってDOMから削除される場合replacehtmlなど) 。これにより、基本的に、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」の両方に配置し、バインドを解除する場合は、「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 16

3

私はjQueryの特別なイベントを使用したmtkoponeの答えが好きですが、それが機能しないことに注意してください。


3
質問は.remove()の使用をデタッチではなく明示的に要求したため、反対票を投じました。detachエレメントはおそらく後で再接続される予定であるため、クリーンアップをトリガーしないために特に使用されます。b)少なくともDOM変異イベントが広く実装されているため、まだ真実であり、信頼できる処理がありません。
ピエール

4
「批評家」のバッジを取得するためだけにこれを実行したに違いない;)
Charon 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 2010

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
それを自由にできるのは素晴らしいことです。残念ながら、mutation-eventsは非推奨となっているため、信頼性は高くありません: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の回答を参照:

他の機能でSOOしたい場合。私の場合のように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
DOMNodeRemovedFromDocumentはFirefoxではサポートされていないようです。おそらく代わりにMutationObserverを試してください。
EricP 2014年

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.