jQuery Event: Mendeteksi perubahan pada html / teks div

265

Aku punya div yang memiliki isinya berubah sepanjang waktu, baik itu ajax requests, jquery functions, blurdll dll

Apakah ada cara saya dapat mendeteksi perubahan pada div saya pada suatu titik waktu?

Saya tidak ingin menggunakan interval atau nilai default yang dicentang.

Sesuatu seperti ini akan dilakukan

$('mydiv').contentchanged() {
 alert('changed')
}
BoqBoq
sumber
5
Kemungkinan rangkap: stackoverflow.com/questions/10328102/…
Rob
14
@Rob Itu mengikat keypressacara ke <div>elemen yang dapat diedit . Saya tidak yakin solusi di sana berlaku untuk ini. Mereka pasti tidak akan mengambil perubahan terprogram untuk konten suatu elemen.
Anthony Grist

Jawaban:

408

Jika Anda tidak ingin menggunakan penghitung waktu dan periksa innerHTML Anda dapat mencoba acara ini

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

Lebih detail dan data dukungan peramban ada di Sini .

Perhatian: di versi jQuery yang lebih baru, bind () sudah usang, jadi Anda harus menggunakan on () sebagai gantinya:

$('body').on('DOMSubtreeModified', 'mydiv', function(){
  console.log('changed');
});
iman
sumber
14
Perlu diingat DOMSubtreeModified tidak didukung di IE8 (dan di bawah).
Gavin
56
acara ini sudah ditinggalkan w3.org/TR/DOM-Level-3-Events/#glossary-deprecated
Isaiyavan Babu Karan
3
Mozilla 33: jatuh dalam rekursi untuk elemen <body>. Perlu menemukan cara lain
Chaki_Black
17
Ini serius, JANGAN gunakan acara ini karena itu akan merusak semua pekerjaan Anda karena dipecat setiap saat. Alih-alih gunakan peristiwa di bawah $ ('. MyDiv') .bind ('DOMNodeInserted DOMNodeRemoved', function () {});
George SEDRA
19
Metode ini sudah usang! Alih-alih gunakan:$("body").on('DOMSubtreeModified', "mydiv", function() { });
Asif
55

Menggunakan 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);
PPB
sumber
6
Ini adalah jawaban yang benar karena sekarang lebih disukai daripada menggunakan DOMSubtreeModified
Joel Davey
3
Saya mendapatkan kesalahan dengan ini, meskipun saya telah memberikan pemilih yang benar. "VM21504: 819 UnEught TypeError: Gagal menjalankan 'amati' pada 'MutationObserver': parameter 1 bukan tipe 'Node'."
samir
54

Karena $("#selector").bind()sudah usang , Anda harus menggunakan:

$("body").on('DOMSubtreeModified', "#selector", function() {
    // code here
});
Petar Nikov
sumber
1
Ini adalah faktor pembeda, tambahan #untuk menunjukkan bahwa simbol harus ada sebelum pemilih.
Chris - Jr
42

Anda bisa mencoba ini

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

});

tetapi ini mungkin tidak berfungsi di internet explorer, belum mengujinya

pengguna1790464
sumber
3
CATATAN !: jika Anda menggunakan ini untuk pemicu dan ada banyak perubahan yang dilakukan pada halaman - itu akan menjalankan fungsi Anda X kali (bahkan mungkin X = 1.000 atau lebih) yang bisa sangat tidak efisien. Salah satu solusi sederhana adalah dengan mendefinisikan "running" boolean var, itu akan ... if (running == true) {return} ... tanpa menjalankan kode Anda jika sudah berjalan. Set running = true tepat setelah logika if Anda, dan running = false sebelum fungsi Anda keluar. Anda juga dapat menggunakan timer untuk membatasi fungsi Anda agar hanya dapat berjalan setiap X detik. running = true; setTimeout (function () {running = false}, 5000); (atau sesuatu yang lebih baik)
JxAxMxIxN
Saya menggunakan ini pada kotak pilih yang memiliki opsi yang ditambahkan dan dihapus. Ini bekerja dengan baik ketika item ditambahkan tetapi penghapusan tampaknya ada 1 item di belakang. Ketika opsi terakhir dihapus, itu tidak akan menyala.
CodeMonkey
2
@ JxAxMxIxN Anda juga dapat menabrak penghitung waktu habis dengan menghapus & mengatur batas waktu lagi:clearTimeout(window.something); window.something = setTimeout(...);
Ctrl-C
setuju - cara Anda adalah jalan yang harus ditempuh - karena belajar Python Saya telah membersihkan banyak praktik pengkodean yang buruk di berbagai bahasa (tidak semua, hanya banyak;)
JxAxMxIxN
33

Anda mencari MutationObserver atau Acara Mutasi . Tidak didukung di mana-mana dan tidak dipandang terlalu sayang oleh dunia pengembang.

Jika Anda tahu (dan dapat memastikan bahwa) ukuran div akan berubah, Anda mungkin dapat menggunakan event resize crossbrowser .

rodneyrehm
sumber
1
Ini adalah salah satunya. Secara khusus, DOMSubtreeModified . Anda mungkin menemukan perpustakaan ringkasan mutasi bermanfaat, dan daftar Acara DOM Tree ini .
BenjaminRH
1
acara ini sudah ditinggalkan developer.mozilla.org/en-US/docs/Web/Guide/Events/…
Adrien Be
9
Jika ada orang lain yang harus mencoba membaca semuanya di mana-mana, ini adalah jawaban yang benar. Acara Mutasi didukung di peramban sebelumnya, Pengamat Mutasi adalah yang akan didukung di peramban modern dan akan didukung di masa mendatang. Lihat tautan untuk dukungan: CANIUSE Mutation Observer
Josh Mc
20

Kode berikut berfungsi untuk saya.

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

Semoga ini bisa membantu seseorang :)

Sanchit Gupta
sumber
Ini adalah jawaban yang sama dengan yang dari @Artley
Black
@Hitam Terima kasih! Saya baru saja memeriksa jawaban Artley. Saya akan mengurus ini nanti.
Sanchit Gupta
17

Tidak ada solusi bawaan untuk masalah ini, ini adalah masalah dengan desain dan pola pengkodean Anda.

Anda dapat menggunakan pola penerbit / pelanggan. Untuk ini, Anda dapat menggunakan acara khusus jQuery atau mekanisme acara Anda sendiri.

Pertama,

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

Sekarang Anda dapat berlangganan acara divhtmlchanging / divhtmlchanged sebagai berikut,

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

Sekarang, Anda harus mengubah perubahan konten div Anda melalui changeHtml()fungsi ini . Jadi, Anda dapat memantau atau dapat melakukan perubahan yang diperlukan karena mengikat argumen data panggilan balik yang berisi informasi.

Anda harus mengubah html div Anda seperti ini;

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

Dan juga, Anda dapat menggunakan ini untuk elemen html apa pun kecuali elemen input. Pokoknya Anda dapat memodifikasi ini untuk digunakan dengan elemen apa saja.

Sameera Millavithanachchi
sumber
Untuk mengamati dan bertindak atas perubahan pada elemen tertentu, cukup modifikasi fungsi changeHtml untuk menggunakan 'elem.trigger (...)' alih-alih 'jQuery.event.trigger (...)', dan kemudian ikat ke elemen seperti $ ('# my_element_id'). on ('htmlchanged', fungsi (e, data) {...}
KenB
8
"Ini masalah dengan desain dan pola pengkodean Anda", apa yang harus dilakukan jika Anda menyertakan skrip pihak ketiga sehingga Anda tidak memiliki kendali pada kode sumbernya? tetapi Anda perlu mendeteksi perubahan mereka ke satu div?
DrLightman
@DrLightman aturan praktisnya adalah memilih lib pihak ketiga dengan acara callback yang disediakan
Marcel Djaman
8

Gunakan MutationObserver seperti yang terlihat dalam cuplikan ini yang disediakan oleh Mozilla , dan diadaptasi dari posting blog ini

Atau, Anda dapat menggunakan contoh JQuery yang terlihat di tautan ini

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();
Anthony Awuley
sumber
3

Anda bisa menyimpan innerHTML lama dari div dalam sebuah variabel. Tetapkan interval untuk memeriksa apakah konten lama cocok dengan konten saat ini. Ketika ini tidak benar, lakukan sesuatu.

codelove
sumber
1

Coba MutationObserver:

dukungan browser: 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>

juFo
sumber
0

Menambahkan beberapa konten ke div, baik melalui jQuery atau via de DOM-API secara langsung, default ke .appendChild()fungsi. Yang dapat Anda lakukan adalah menimpa .appendChild()fungsi objek saat ini dan menerapkan pengamat di dalamnya. Sekarang setelah mengganti .appendChild()fungsi kami , kami perlu meminjam fungsi itu dari objek lain untuk dapat menambahkan konten. Untuk itu kami memanggil .appendChild()div lain untuk akhirnya menambahkan konten. Tentu, ini juga diperhitungkan untuk .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);
        }
    };

Di sini Anda dapat menemukan contoh naif. Anda bisa memperpanjangnya sendiri, saya kira. http://jsfiddle.net/RKLmA/31/

Ngomong-ngomong: ini menunjukkan JavaScript mematuhi prinsip OpenClosed. :)

Andries
sumber
Ini tidak berfungsi dengan append child ... Saya benar-benar memodifikasi html melalui fungsi lain.
BoqBoq
Seperti removeChild () replaceChild () dll. Tapi Anda benar di innerHTML. Anda harus menghindarinya entah bagaimana.
Andries