web-dev-qa-db-ja.com

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

ありがとう。

200
sa125

チェックしただけで、現在のバージョンの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/

112
Philipp Munin

これには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') { ... }に変更します

194
mtkopone

DOMNodeRemovedイベント(DOMレベル3 WC3仕様の一部)にバインドできます。

IE9、FirefoxおよびChromeの最新リリースで動作します。

例:

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

DOMNodeInsertedにバインドすることで、要素が挿入されたときに通知を受け取ることもできます

47
Adam

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

37
David Hellsing

.remove() をフックすることは、ページから要素を削除する多くの方法があるため、これを処理する最良の方法ではありません(たとえば、 .html().replace() 、等)。

さまざまなメモリリークの危険を防ぐために、内部的にjQueryは関数jQuery.cleanData()を呼び出そうとしますが、削除に使用されるメソッド。

詳細については、この回答を参照してください: javascript memory leaks

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

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

32
zah

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

このソリューションでは、イベントハンドラーをunbindすることもできます。

$("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
Legends

この答え をアンバインドで動作させることはできませんでしたが(更新 ここを参照 にもかかわらず)、それを回避する方法を見つけることができました。答えは、「destroyed」イベントをトリガーする「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++;
});

フィドル

4
Bill Johnston

JQueryの特別なイベントを使用したmtkoponeの答えが好きですが、a)要素が削除されずにデタッチされたとき、またはb)いくつかの古い非jqueryライブラリがinnerHTMLを使用して要素を破棄するときは機能しないことに注意してください

3
Charon ME

これが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)
  }
});
1
Buzogany Laszlo

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要素は削除されます。

1
philippe

このためのイベントハンドルがあるかどうかはわかりません。そのため、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
Fenton

@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
Patryk M

この。

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