jQuery Olayı: Bir div'ın html / metnindeki değişiklikleri algılama


265

İçeriği her zaman değişen bir divim var ajax requests, olsun jquery functions, blurvb.

Div'imde herhangi bir zamanda herhangi bir değişikliği tespit edebilmemin bir yolu var mı?

Kontrol edilen herhangi bir aralık veya varsayılan değer kullanmak istemiyorum.

Böyle bir şey yapardı

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


14
@Rob Bu, bir keypressolayı içerikli bir <div>öğeye bağlar . Buradaki çözümlerin bunun için geçerli olduğundan emin değilim. Kesinlikle bir öğenin içeriğinde herhangi bir programatik değişiklik almayacaklardı.
Anthony Grist

Yanıtlar:


407

Zamanlayıcı kullanmak ve innerHTML'yi kontrol etmek istemiyorsanız bu etkinliği deneyebilirsiniz

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

Daha fazla ayrıntı ve tarayıcı desteği verileri burada .

Dikkat: daha yeni jQuery sürümlerinde bind () kullanımdan kaldırılmıştır, bunun yerine on () öğesini kullanmalısınız:

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

14
Unutmayın DOMSubtreeModified, IE8'de (ve aşağıda) desteklenmez.
Gavin


3
Mozilla 33: <body> öğesi için özyinelemeye düştü. Başka bir yol bulmak gerekiyor
Chaki_Black

17
Ciddi bu olayı KULLANMAYIN çünkü her zaman ateşlendiğinden tüm işinizi çökecektir. Bunun yerine $ ('. MyDiv') altındaki olayları kullanın. Bind ('DOMNodeInserted DOMNodeRemoved', function () {});
George SEDRA

19
Bu yöntem kullanımdan kaldırıldı! Bunun yerine kullanın:$("body").on('DOMSubtreeModified', "mydiv", function() { });
Asif

55

Javascript MutationObserver kullanma

  //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
Joel Davey

3
Doğru seçiciyi vermiş olmama rağmen bu konuda hata alıyorum. "VM21504: 819 Yakalanmayan TypeError: 'MutationObserver' üzerinde 'gözlemle' çalıştırılamadı: parametre 1 'Düğüm' tipinde değil."
samir


42

Bunu deneyebilirsin

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

});

ama bu internet explorer'da çalışmayabilir, test etmedim


10
Yoksun: geliştirici.mozilla.org/ tr-TR/docs/Web/Guide/Events/… Yerine kullanın: developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Randall Flagg

3
NOT !: bunu bir tetikleyici için kullanırsanız ve sayfada çok fazla değişiklik yapılıyorsa - çok verimli olmayan X işlevini (belki X = 1,000 veya daha fazla) çalıştıracaktır. Basit bir çözüm, zaten çalışıyorsa kodunuzu çalıştırmadan ... if (running == true) {return} ... yapacak bir "running" boolean var tanımlamaktır. İf mantığınızdan hemen sonra running = true, işlevinizden çıkmadan önce running = false olarak ayarlayın. Zamanlayıcıyı işlevinizi yalnızca her X saniyede bir çalışacak şekilde sınırlamak için de kullanabilirsiniz. = Gerçek çalışan; setTimeout (fonksiyonu () {çalışan = kapalı}, 5000); (ya da daha iyi bir şey)
JxAxMxIxN

Bunu, eklenen ve kaldırılan seçeneklerin bulunduğu bir seçim kutusunda kullandım. Öğeler eklendiğinde harika çalıştı, ancak kaldırmanın arkasında 1 öğe var gibi görünüyordu. Son seçenek kaldırıldığında ateş etmeyecekti.
CodeMonkey

2
@JxAxMxIxN Zaman aşımı zamanlayıcısını yeniden temizleyerek ve ayarlayarak da zaman aşımı zamanlayıcısını çarpabilirsiniz:clearTimeout(window.something); window.something = setTimeout(...);
Ctrl-C

kabul etti - senin yolun yoludur - Python'u öğrendiğimden beri, birçok dilde zayıf kodlama uygulamalarımın çoğunu temizledim (hepsi değil, sadece çok;)
JxAxMxIxN

33

MutationObserver veya Mutation Etkinlikleri arıyorsunuz . Ne her yerde destekleniyor ne de geliştirici dünya tarafından çok seviliyor.

Div'in boyutunun değişeceğini biliyorsanız (ve bundan emin olabilirseniz), tarayıcılar arası yeniden boyutlandırma etkinliğini kullanabilirsiniz .


1
İşte bu o. Özellikle, DOMSubtreeModified . Mutasyon özeti kitaplığını ve bu DOM Ağacı Etkinlikleri listesini yararlı bulabilirsiniz .
BenjaminRH


9
Herkesin her yerde her şeyi okumak zorunda kalması durumunda, doğru cevap budur. Mutasyon Etkinlikleri geçmiş tarayıcılarda desteklendi, Mutation Observer modern tarayıcılarda desteklenecek ve gelecekte desteklenecek olan şey. Destek için bağlantıya bakın: CANIUSE Mutation Observer
Josh Mc

20

Aşağıdaki kod benim için çalışıyor.

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

Birisine yardımcı olacağını umuyoruz :)


Bu, @Artley
Black

@Black Thankyou! Artley cevabını kontrol ettim. Bir dahaki sefere bununla ilgileneceğim.
Sanchit Gupta

17

Bu sorunun dahili bir çözümü yoktur, bu tasarım ve kodlama deseninizle ilgili bir sorundur.

Yayıncı / abone kalıbını kullanabilirsiniz. Bunun için jQuery özel etkinliklerini veya kendi etkinlik mekanizmanızı kullanabilirsiniz.

İlk,

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

Artık divhtmlchanging / divhtmlchanged etkinliklerine aşağıdaki gibi abone olabilirsiniz,

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

Şimdi, div içeriği değişikliklerinizi bu changeHtml()işlev aracılığıyla değiştirmeniz gerekir . Bu nedenle, bilgileri içeren geri arama verisi bağımsız değişkenini bağlama nedeniyle gerekli değişiklikleri izleyebilir veya yapabilirsiniz.

Div'inizin html'sini şu şekilde değiştirmeniz gerekir;

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

Ayrıca, bunu giriş öğesi hariç herhangi bir html öğesi için kullanabilirsiniz. Her neyse, bunu herhangi bir öğeyle kullanmak için değiştirebilirsiniz.


Belirli bir öğedeki değişiklikleri gözlemlemek ve bunlara göre hareket etmek için, 'jQuery.event.trigger (...)' yerine 'elem.trigger (...)' kullanacak şekilde changeHtml işlevini değiştirmeniz ve ardından aşağıdaki öğeye bağlamanız yeterlidir. $ ('# my_element_id'). on ('htmlchanged', işlev (e, veri) {...}
KenB

8
"Bu, tasarım ve kodlama kalıbınızla ilgili bir sorundur", üçüncü taraf komut dosyaları eklerseniz ne yapmalısınız? ancak bir div'da değişikliklerini tespit etmeniz mi gerekiyor?
DrLightman

@DrLightman sağlanan bir geri arama olayı ile üçüncü taraf lib seçmek için başparmak
Marcel Djaman

8

Mozilla tarafından sağlanan ve bu blog yayınından uyarlanan bu snippet'te görüldüğü gibi MutationObserver'ı kullanın

Alternatif olarak, bu bağlantıda görülen JQuery örneğini kullanabilirsiniz

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 öğesinin eski innerHTML'sini bir değişkende saklayabilirsiniz. Eski içeriğin geçerli içerikle eşleşip eşleşmediğini kontrol etmek için bir aralık ayarlayın. Bu doğru olmadığında bir şey yapın.


1

MutationObserver'ı deneyin:

tarayıcı desteği: 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

Bir div'e, jQuery veya doğrudan DOM-API yoluyla bir miktar içerik eklemek varsayılan olarak .appendChild()işlevin varsayılan değeridir . Yapabileceğiniz şey, .appendChild()mevcut nesnenin işlevini geçersiz kılmak ve bu nesneye bir gözlemci uygulamaktır. Şimdi .appendChild()işlevimizi geçersiz kıldığımızda, içeriği ekleyebilmek için bu işlevi başka bir nesneden ödünç almamız gerekiyor. Bu nedenle .appendChild(), içeriği eklemek için başka bir div adını veriyoruz. Tabii ki, bu da önemlidir .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);
        }
    };

Burada naif bir örnek bulabilirsiniz. Bunu kendiniz uzatabilirsiniz sanırım. http://jsfiddle.net/RKLmA/31/

Bu arada: Bu JavaScript'in OpenClosed prensibine uygun olduğunu gösterir. :)


Append child ile çalışmaz ... Aslında html'sini diğer fonksiyonlarla değiştiriyorum.
BoqBoq

RemoveChild () replaceChild () vb. Gibi. Ama innerHTML'de haklısınız. Bir şekilde bundan kaçınmalısınız.
Mart'ta Andries
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.