jQuery Event: ตรวจจับการเปลี่ยนแปลงใน html / text ของ div


265

ฉันมี div ซึ่งมีเนื้อหาเปลี่ยนแปลงอยู่ตลอดเวลาไม่ว่าจะเป็นajax requests, jquery functions, blurฯลฯ เป็นต้น

มีวิธีที่ฉันสามารถตรวจจับการเปลี่ยนแปลงใด ๆ ใน div ของฉันได้ตลอดเวลาหรือไม่?

ฉันไม่ต้องการใช้ช่วงเวลาหรือการตรวจสอบค่าเริ่มต้น

สิ่งนี้จะทำ

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

5
ซ้ำซ้อนที่เป็นไปได้: stackoverflow.com/questions/10328102/…
Rob

14
@Rob นั่นเป็นการเชื่อมโยงkeypressเหตุการณ์กับ<div>องค์ประกอบที่พึงพอใจ ฉันไม่แน่ใจว่าวิธีแก้ปัญหาที่ใช้กับสิ่งนี้ แน่นอนว่าพวกเขาจะไม่รับการเปลี่ยนแปลงเชิงโปรแกรมใด ๆ ต่อเนื้อหาขององค์ประกอบ
Anthony Grist

คำตอบ:


407

หากคุณไม่ต้องการใช้ตัวจับเวลาและตรวจสอบ InnerHTML คุณสามารถลองกิจกรรมนี้ได้

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

รายละเอียดเพิ่มเติมและข้อมูลการสนับสนุนเบราว์เซอร์ที่นี่

ข้อควรสนใจ:ใน jQuery เวอร์ชันใหม่กว่าผูก () เลิกใช้แล้วดังนั้นคุณควรใช้กับ () แทน:

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

14
โปรดทราบว่า DOMSubtreeModified ไม่รองรับ IE8 (และด้านล่าง)
กาวิน

56
เหตุการณ์นี้เลิกใช้แล้วw3.org/TR/DOM-Level-3-Events/#glossary-deprecated
Isaiyavan Babu Karan

3
Mozilla 33: มีการเรียกซ้ำสำหรับองค์ประกอบ <body> จำเป็นต้องหาวิธีอื่น
Chaki_Black

17
มันร้ายแรงอย่าใช้เหตุการณ์นี้มันจะพังงานทั้งหมดของคุณเพราะมันถูกไล่ออกตลอดเวลา ใช้เหตุการณ์ด้านล่าง $ ('. myDiv') แทนการผูก ('DOMNodeInserted DOMNodeRemoved', function () {});
George SEDRA

19
วิธีนี้เลิกใช้แล้ว! ใช้แทน:$("body").on('DOMSubtreeModified', "mydiv", function() { });
Asif

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

3
ฉันได้รับข้อผิดพลาดจากสิ่งนี้ถึงแม้ว่าฉันจะให้ตัวเลือกที่ถูกต้อง "VM21504: 819 Uncaught TypeError: ล้มเหลวในการดำเนินการ 'สังเกต' บน 'MutationObserver': พารามิเตอร์ 1 ไม่ใช่ประเภท 'Node'"
samir


42

คุณสามารถลองสิ่งนี้

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

});

แต่สิ่งนี้อาจไม่ทำงานใน internet explorer ไม่ได้ทำการทดสอบ



3
หมายเหตุ!: หากคุณใช้สิ่งนี้เพื่อการทริกเกอร์และมีการเปลี่ยนแปลงจำนวนมากในหน้า - มันจะเรียกใช้ฟังก์ชัน X ครั้ง (อาจเป็น X = 1,000 หรือมากกว่า) ซึ่งอาจไม่มีประสิทธิภาพมาก วิธีแก้ไขปัญหาอย่างง่ายอย่างหนึ่งคือการกำหนดบูลีน "ที่กำลังทำงาน" นั่นจะ ... หาก (กำลังทำงาน == จริง) {return} ... โดยไม่ต้องเรียกใช้รหัสของคุณหากมันกำลังทำงานอยู่ ตั้งค่า running = true หลังจากตรรกะ if ของคุณและ running = false ก่อนที่ฟังก์ชันของคุณจะออก คุณสามารถใช้ตัวจับเวลาเพื่อ จำกัด ฟังก์ชั่นของคุณให้สามารถเรียกใช้ทุก ๆ สิบวินาทีเท่านั้น ทำงาน = true; setTimeout (ฟังก์ชั่น () {ทำงาน = false}, 5000); (หรืออะไรที่ดีกว่า)
JxAxMxIxN

ฉันใช้สิ่งนี้ในกล่องเลือกที่มีตัวเลือกการเพิ่มและลบ มันใช้งานได้ดีเมื่อมีการเพิ่มรายการ แต่การลบดูเหมือนจะเป็น 1 รายการ เมื่อตัวเลือกสุดท้ายถูกลบออกมันจะไม่ทำงาน
CodeMonkey

2
@JxAxMxIxN นอกจากนี้คุณยังสามารถชนจับเวลาการหมดเวลาโดยการล้าง & ตั้งค่าการหมดเวลาอีกครั้ง:clearTimeout(window.something); window.something = setTimeout(...);
Ctrl-C

ตกลงกัน - ทางของคุณเป็นวิธีที่จะไป - ตั้งแต่การเรียนรู้หลามผมเคยล้างขึ้นจำนวนมากของการปฏิบัติการเข้ารหัสของฉันที่ไม่ดีในหลายภาษา (ไม่ทั้งหมดเพียงมาก;)
JxAxMxIxN

33

คุณกำลังมองหาMutationObserverหรือการกลายพันธุ์เหตุการณ์ ไม่ได้รับการสนับสนุนในทุกที่และไม่ได้รับการสนับสนุนจากโลกของนักพัฒนา

หากคุณรู้ (และสามารถมั่นใจได้ว่า) ขนาดของ div จะเปลี่ยนไปคุณอาจสามารถใช้การปรับขนาด crossbrowserได้


1
นี่คือหนึ่ง โดยเฉพาะDOMSubtreeModified คุณอาจพบว่าการกลายพันธุ์สรุปห้องสมุดที่เป็นประโยชน์และรายการนี้โครงสร้างต้นไม้ DOM เหตุการณ์
BenjaminRH

1
กิจกรรมนี้เลิกใช้แล้วdeveloper.mozilla.org/en-US/docs/Web/Guide/Events/…
Adrien Be

9
ในกรณีที่คนอื่นต้องลองอ่านทุกอย่างทุกที่นี่เป็นคำตอบที่ถูกต้อง เหตุการณ์การกลายพันธุ์ได้รับการสนับสนุนในเบราว์เซอร์ที่ผ่านมาผู้สังเกตการณ์การกลายพันธุ์คือสิ่งที่จะได้รับการสนับสนุนในเบราว์เซอร์ที่ทันสมัยและจะได้รับการสนับสนุนในอนาคต ดูลิงค์สำหรับการสนับสนุน: CANIUSE Mutation Observer
Josh Mc

20

รหัสต่อไปนี้ทำงานให้ฉัน

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

หวังว่ามันจะช่วยให้ใครบางคน :)


นี่เป็นคำตอบเดียวกับ @Artley
Black

@ ดำขอบคุณมาก! ฉันเพิ่งตรวจสอบคำตอบของ Artley ฉันจะดูแลในครั้งต่อไป
Sanchit Gupta

17

ไม่มีวิธีแก้ปัญหาแบบ inbuilt ปัญหานี้เป็นปัญหากับการออกแบบและรูปแบบการเข้ารหัสของคุณ

คุณสามารถใช้รูปแบบผู้เผยแพร่ / สมาชิก สำหรับสิ่งนี้คุณสามารถใช้เหตุการณ์ที่กำหนดเอง 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
});

ตอนนี้คุณต้องเปลี่ยนการเปลี่ยนแปลงเนื้อหา div ผ่านchangeHtml()ฟังก์ชั่นนี้ ดังนั้นคุณสามารถตรวจสอบหรือสามารถทำการเปลี่ยนแปลงที่จำเป็นตามเพราะผูกอาร์กิวเมนต์ข้อมูลโทรกลับที่มีข้อมูล

คุณต้องเปลี่ยน html div ของคุณเช่นนี้

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

และคุณสามารถใช้สิ่งนี้กับองค์ประกอบ html ใด ๆ ยกเว้นองค์ประกอบอินพุต อย่างไรก็ตามคุณสามารถแก้ไขสิ่งนี้เพื่อใช้กับองค์ประกอบใด ๆ


หากต้องการสังเกตและดำเนินการเปลี่ยนแปลงองค์ประกอบเฉพาะเพียงแก้ไขฟังก์ชัน changeHtml เพื่อใช้ 'elem.trigger (... )' แทน 'jQuery.event.trigger (... )' แล้วผูกเข้ากับองค์ประกอบเช่น $ ('# my_element_id'). on ('htmlchanged', ฟังก์ชั่น (e, data) {... }
KenB

8
"นี่เป็นปัญหาของการออกแบบและรูปแบบการเข้ารหัสของคุณ" จะทำอย่างไรถ้าคุณใส่สคริปต์บุคคลที่สามดังนั้นคุณจึงไม่สามารถควบคุมซอร์สโค้ดของพวกเขาได้ แต่คุณต้องตรวจสอบการเปลี่ยนแปลงของพวกเขาเป็นหนึ่ง div?
DrLightman

@DLLightman กฎของหัวแม่มือคือการเลือก lib บุคคลที่สามกับเหตุการณ์โทรกลับให้
Marcel Djaman

8

ใช้MutationObserverตามที่เห็นในตัวอย่างนี้จัดทำโดยMozillaและดัดแปลงจากโพสต์บล็อก

หรือคุณสามารถใช้ตัวอย่าง 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

คุณสามารถเก็บ InnerHTML เก่าของ div ในตัวแปรได้ กำหนดช่วงเวลาเพื่อตรวจสอบว่าเนื้อหาเก่าตรงกับเนื้อหาปัจจุบันหรือไม่ เมื่อสิ่งนี้ไม่เป็นความจริงให้ทำอะไรสักอย่าง


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

การเพิ่มเนื้อหาบางส่วนให้กับ div ไม่ว่าจะผ่าน jQuery หรือผ่าน de DOM-API โดยตรงจะใช้ค่าเริ่มต้นใน.appendChild()ฟังก์ชัน สิ่งที่คุณสามารถทำได้คือแทนที่.appendChild()ฟังก์ชั่นของวัตถุปัจจุบันและนำผู้สังเกตการณ์มาใช้ ตอนนี้แทนที่.appendChild()ฟังก์ชันของเราแล้วเราต้องยืมฟังก์ชันนั้นจากวัตถุอื่นเพื่อให้สามารถผนวกเนื้อหา ด้วยเหตุนี้เราจึงเรียกตัวแทน.appendChild()ของอีกฝ่ายหนึ่งมาผนวกท้ายเนื้อหา ofcourse .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/

โดยวิธีการนี :)


มันไม่ทำงานกับลูกผนวก ... ฉันจริง ๆ แล้วแก้ไข html ของมันผ่านฟังก์ชั่นอื่น ๆ
BoqBoq

เช่นเดียวกับ removeChild () replaceChild () ฯลฯ แต่คุณอยู่ใน innerHTML คุณควรหลีกเลี่ยงมันอย่างใด
Andries
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.