jQueryイベント:divのhtml / textへの変更を検出します


265

私はすべての時間を変更し、その内容を持っているdiv要素を持っている、それもajax requestsjquery functionsblurなどなど

divの変更をいつでも検出できる方法はありますか?

チェックされている間隔やデフォルト値を使用したくありません。

このような何かがします

$('mydiv').contentchanged() {
 alert('changed')
}


14
@Robこれは、keypressイベントをcontenteditable <div>要素にバインドしています。そこにある解決策がこれに当てはまるかどうかはわかりません。彼らは間違いなく、要素のコンテンツへのプログラムによる変更を拾いません。
Anthony Grist 2013年

回答:


408

タイマーを使用せず、innerHTMLを確認したくない場合は、このイベントを試すことができます

$('mydiv').bind('DOMSubtreeModified', function(){
  console.log('changed');
});

詳細とブラウザのサポートデータはこちらです。

注意:新しいjQueryバージョンではbind()は非推奨であるため、代わりにon()を使用する必要があります。

$('body').on('DOMSubtreeModified', 'mydiv', function(){
  console.log('changed');
});

14
DOMSubtreeModifiedはIE8以降ではサポートされていないことに注意してください。
ギャビン


3
Mozilla 33:要素<body>の再帰に陥りました。別の方法を見つける必要がありました
Chaki_Black 2014年

17
このイベントを使用しないでください。常に発生するすべての作業cosがクラッシュします。代わりに、$( '。myDiv')。bind( 'DOMNodeInserted DOMNodeRemoved'、function(){});の下のイベントを使用してください。
ジョージセドラ2016

19
このメソッドは廃止されました!代わりに使用:$("body").on('DOMSubtreeModified', "mydiv", function() { });
アシフ

55

JavaScript MutationObserverの使用

  //More Details https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
 // select the target node
var target = document.querySelector('mydiv')
// create an observer instance
var observer = new MutationObserver(function(mutations) {
  console.log($('mydiv').text());   
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);

6
これは今DOMSubtreeModifiedを使用してより優先されるので、これは正しい答えである
ジョエル・デイビー

3
正しいセレクタを指定しているにもかかわらず、これでエラーが発生します。「VM21504:819 Uncaught TypeError: 'MobationObserver'で 'observe'を実行できませんでした:パラメーター1のタイプが 'Node'ではありません。
サミール


42

あなたはこれを試すことができます

$('.myDiv').bind('DOMNodeInserted DOMNodeRemoved', function() {

});

しかし、これはInternet Explorerでは機能しない可能性があり、テストしていません



3
注!:これをトリガーに使用し、ページに多くの変更が加えられている場合、関数はX回(おそらくX = 1,000以上でも)実行されますが、非常に非効率的です。簡単な解決策の1つは、「実行中」のブール変数を定義することです。if(running == true){return} ...すでに実行されている場合は、コードを実行しません。ifロジックの直後にrunning = trueを設定し、関数が終了する前にrunning = falseを設定します。タイマーを使用して、関数をX秒ごとにのみ実行できるように制限することもできます。running = true; setTimeout(function(){running = false}、5000); (またはより良いもの)
JxAxMxIxN

これは、オプションが追加および削除される選択ボックスで使用しました。アイテムが追加されたときはうまくいきましたが、削除は1アイテム遅れているようです。最後のオプションが削除されたとき、それは発砲しませんでした。
CodeMonkey 2017年

2
@JxAxMxIxNます。また、クリアでタイムアウトタイマーをバンプ&再びタイムアウトを設定することができますclearTimeout(window.something); window.something = setTimeout(...);
Ctrl-Cを

合意された-あなたの方法を移動するための方法である-複数の言語間で私の貧弱なコーディング手法の多く片付けてきたPythonの私を学ぶため、(すべてではない、ただたくさん;)
JxAxMxIxN

33

MutationObserverまたはMutation Eventsを探しています。どちらもどこでもサポートされておらず、開発者の世界からあまりにも好意的に見られているわけでもありません。

divのサイズが変更されることがわかっている(確認できる)場合、クロスブラウザーのサイズ変更イベントを使用できる可能性があります。


1
これです。具体的には、DOMSubtreeModifiedMutation-SummaryライブラリとDOM Tree Eventsのこのリストが役立つかもしれません。
BenjaminRH


9
他の誰かがどこでもすべてを読み通すことを試みなければならなかった場合、これは正しい答えです。突然変異イベントは過去のブラウザーでサポートされていました。突然変異オブザーバーは、最新のブラウザーでサポートされ、将来サポートされるものです。サポートについては、リンクを参照してください。CANIUSEMutation Observer
Josh Mc

20

次のコードは私のために働きます。

$("body").on('DOMSubtreeModified', "mydiv", function() {
    alert('changed');
});

それが誰かを助けることを願っています:)


これは、@ Artleyからの回答と同じ回答です
ブラック

@ブラックサンキュー!Artleyの回答を確認しました。次回はこれを担当します。
Sanchit Gupta

17

この問題に対する組み込みの解決策はありません。これは、設計とコーディングパターンの問題です。

パブリッシャー/サブスクライバーパターンを使用できます。これには、jQueryカスタムイベントまたは独自のイベントメカニズムを使用できます。

最初、

function changeHtml(selector, html) {
    var elem = $(selector);
    jQuery.event.trigger('htmlchanging', { elements: elem, content: { current: elem.html(), pending: html} });
    elem.html(html);
    jQuery.event.trigger('htmlchanged', { elements: elem, content: html });
}

これで、divhtmlchanging / divhtmlchangedイベントを次のようにサブスクライブできます。

$(document).bind('htmlchanging', function (e, data) {
    //your before changing html, logic goes here
});

$(document).bind('htmlchanged', function (e, data) {
    //your after changed html, logic goes here
});

次に、このchangeHtml()関数を使用してdivコンテンツの変更を変更する必要があります。したがって、情報を含むコールバックデータ引数をバインドするため、必要に応じて監視したり必要な変更を行ったりできます。

このようにdivのhtmlを変更する必要があります。

changeHtml('#mydiv', '<p>test content</p>');

また、これはinput要素を除くすべてのhtml要素に使用できます。とにかく、これを変更して任意の要素で使用できます。


特定の要素の変更を観察して操作するには、「jQuery.event.trigger(...)」の代わりに「elem.trigger(...)」を使用するようにchangeHtml関数を変更し、次のように要素にバインドします。 $( '#my_element_id')。on( 'htmlchanged'、function(e、data){...}
KenB

8
「これは設計とコーディングパターンの問題です」、サードパーティのスクリプトを含める場合はどうすればよいですか。そのため、ソースコードを制御できません。しかし、1つのdivへの変更を検出する必要がありますか?
DrLightman 2016

@DrLightmanの経験則では、コールバックイベントが提供されたサードパーティライブラリを選択します
Marcel Djaman 2017年

8

Mozillaが提供するこのスニペットに示されているように、このブログの投稿から改変されたMutationObserverを使用

または、このリンクにあるJQueryの例を使用できます

Chrome 18以降、Firefox 14以降、IE 11以降、Safari 6以降

// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true };

// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type == 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();

3

divの古いinnerHTMLを変数に格納できます。古いコンテンツが現在のコンテンツと一致するかどうかを確認する間隔を設定します。これが本当でないときは、何かをしてください。


1

MutationObserverを試してください:

ブラウザのサポート:http : //caniuse.com/#feat=mutationobserver

<html>
  <!-- example from Microsoft https://developer.microsoft.com/en-us/microsoft-edge/platform/documentation/dev-guide/dom/mutation-observers/ -->

  <head>
    </head>
  <body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script type="text/javascript">
      // Inspect the array of MutationRecord objects to identify the nature of the change
function mutationObjectCallback(mutationRecordsList) {
  console.log("mutationObjectCallback invoked.");

  mutationRecordsList.forEach(function(mutationRecord) {
    console.log("Type of mutation: " + mutationRecord.type);
    if ("attributes" === mutationRecord.type) {
      console.log("Old attribute value: " + mutationRecord.oldValue);
    }
  });
}
      
// Create an observer object and assign a callback function
var observerObject = new MutationObserver(mutationObjectCallback);

      // the target to watch, this could be #yourUniqueDiv 
      // we use the body to watch for changes
var targetObject = document.body; 
      
// Register the target node to observe and specify which DOM changes to watch
      
      
observerObject.observe(targetObject, { 
  attributes: true,
  attributeFilter: ["id", "dir"],
  attributeOldValue: true,
  childList: true
});

// This will invoke the mutationObjectCallback function (but only after all script in this
// scope has run). For now, it simply queues a MutationRecord object with the change information
targetObject.appendChild(document.createElement('div'));

// Now a second MutationRecord object will be added, this time for an attribute change
targetObject.dir = 'rtl';


      </script>
    </body>
  </html>


0

jQueryを介して、またはDOM-APIを介して直接、コンテンツをdivに追加すると、デフォルトで.appendChild()関数になります。あなたができることは.appendChild()、現在のオブジェクトの機能をオーバーライドし、それにオブザーバーを実装することです。.appendChild()関数をオーバーライドしたので、コンテンツを追加できるようにするために、他のオブジェクトからその関数を借用する必要があります。そのため.appendChild()、他のdivのを呼び出して、最終的にコンテンツを追加します。もちろん、これはにも当てはまり.removeChild()ます。

var obj = document.getElementById("mydiv");
    obj.appendChild = function(node) {
        alert("changed!");

        // call the .appendChild() function of some other div
        // and pass the current (this) to let the function affect it.
        document.createElement("div").appendChild.call(this, node);
        }
    };

ここでは、単純な例を見つけることができます。自分で拡張できると思います。 http://jsfiddle.net/RKLmA/31/

ちなみに、これはJavaScriptがOpenClosedの原則に準拠していることを示しています。:)


それは子の追加では動作しません...私は実際に他の関数を介してそのhtmlを変更します。
BoqBoq 2013年

removeChild()やreplaceChild()などと同じですが、innerHTMLは正しいです。どういうわけかそれを避けるべきです。
Andries
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.