Sự kiện jQuery: Phát hiện các thay đổi đối với html / văn bản của div


265

Tôi có một div trong đó có nội dung của nó thay đổi tất cả thời gian, có thể là ajax requests, jquery functions, blurvv vv

Có cách nào để tôi có thể phát hiện bất kỳ thay đổi nào trên div của mình tại bất kỳ thời điểm nào không?

Tôi không muốn sử dụng bất kỳ khoảng thời gian hoặc giá trị mặc định được kiểm tra.

Một cái gì đó như thế này sẽ làm

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


14
@Rob Đó là ràng buộc một keypresssự kiện với một <div>yếu tố nội dung. Tôi không chắc các giải pháp ở đó áp dụng cho việc này. Họ chắc chắn sẽ không nhận bất kỳ thay đổi lập trình nào đối với nội dung của một yếu tố.
Anthony Grist

Câu trả lời:


407

Nếu bạn không muốn sử dụng bộ đếm thời gian và kiểm tra bên trongHTML, bạn có thể thử sự kiện này

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

Thông tin chi tiết và dữ liệu hỗ trợ trình duyệt có tại đây .

Chú ý: trong các phiên bản jQuery mới hơn, bind () không được dùng nữa, vì vậy bạn nên sử dụng on () thay thế:

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

14
Hãy nhớ rằng DOMSubtreeModified không được hỗ trợ trong IE8 (và bên dưới).
Gavin

56
sự kiện này không được chấp nhận w3.org/TR/DOM-Level-3-Events/#glossary-deprecated
Isaiyavan Babu Karan

3
Mozilla 33: rơi vào đệ quy cho phần tử <body>. Cần tìm một cách khác
Chaki_Black

17
Thật nghiêm trọng KHÔNG sử dụng sự kiện này, nó sẽ làm hỏng tất cả công việc của bạn vì nó bị sa thải mọi lúc. Thay vào đó, hãy sử dụng các sự kiện bên dưới $ ('. MyDiv'). Bind ('DOMNodeInserted DOMNodeRemond', function () {});
George SEDRA ngày

19
Phương pháp này đã bị phản đối! Thay vào đó hãy sử dụng:$("body").on('DOMSubtreeModified', "mydiv", function() { });
Asif

55

Sử dụng Javascript MutingObserver

  //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
Đây là câu trả lời đúng vì hiện tại nó được ưa chuộng hơn khi sử dụng DOMSubtreeModified
Joel Davey

3
Tôi đang gặp lỗi với điều này, mặc dù tôi đã đưa ra bộ chọn chính xác. "VM21504: 819 Uncaught TypeError: Không thể thực thi 'quan sát' trên 'MutingObserver': tham số 1 không phải là loại 'Nút'."
samir


42

Bạn có thể thử cái này

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

});

nhưng điều này có thể không hoạt động trong internet explorer, chưa thử nghiệm nó



3
LƯU Ý!: Nếu bạn sử dụng công cụ này cho trình kích hoạt và có rất nhiều thay đổi được thực hiện cho trang - nó sẽ chạy chức năng của bạn X lần (thậm chí X = 1.000 trở lên) có thể rất kém hiệu quả. Một giải pháp đơn giản là xác định var boolean "đang chạy", điều đó sẽ ... if (running == true) {return} ... mà không chạy mã của bạn nếu nó đang chạy. Đặt chạy = true ngay sau logic if của bạn và chạy = false trước khi chức năng của bạn thoát. Bạn cũng có thể sử dụng bộ hẹn giờ để giới hạn chức năng của mình chỉ có thể chạy mỗi X giây. chạy = đúng; setTimeout (function () {running = false}, 5000); (hoặc một cái gì đó tốt hơn)
JxAxMxIxN

Tôi đã sử dụng điều này trên một hộp chọn có các tùy chọn được thêm và xóa. Nó hoạt động rất tốt khi các mục được thêm vào nhưng phần xóa dường như là 1 mục phía sau. Khi tùy chọn cuối cùng được gỡ bỏ, nó sẽ không kích hoạt.
CodeMonkey

2
@JxAxMxIxN Bạn cũng có thể giảm thời gian chờ bằng cách xóa và thiết lập lại thời gian chờ:clearTimeout(window.something); window.something = setTimeout(...);
Ctrl-C

đồng ý - con đường của bạn là con đường để đi - kể từ khi học Python, tôi đã xóa rất nhiều thực hành mã hóa kém của mình trên nhiều ngôn ngữ (không phải tất cả, chỉ là rất nhiều;)
JxAxMxIxN

33

Bạn đang tìm kiếm MutationObserver hoặc đột biến sự kiện . Không được hỗ trợ ở khắp mọi nơi và cũng không được thế giới phát triển ưa chuộng.

Nếu bạn biết (và có thể chắc chắn rằng) kích thước của div sẽ thay đổi, bạn có thể sử dụng sự kiện thay đổi kích thước crossbrowser .


1
Đây là một trong những. Cụ thể, DOMSubtreeModified . Bạn có thể thấy thư viện tóm tắt đột biến hữu ích và danh sách Sự kiện Cây DOM này .
BenjaminRH

1
sự kiện này không được chấp developer.mozilla.org/en-US/docs/Web/Guide/Events/...
Adrien Be

9
Bất cứ ai khác đã phải cố gắng đọc qua mọi thứ ở khắp mọi nơi, đây là câu trả lời chính xác. Sự kiện đột biến đã được hỗ trợ trong các trình duyệt trước đây, Trình đột biến là những gì sẽ được hỗ trợ trong các trình duyệt hiện đại và sẽ được hỗ trợ trong tương lai. Xem liên kết để được hỗ trợ: Người quan sát đột biến CANIUSE
Josh Mc

20

Mã sau làm việc cho tôi.

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

Hy vọng nó sẽ giúp được ai đó :)


Đây là câu trả lời tương tự như câu trả lời từ @Artley
Black

@Black Cảm ơn bạn! Tôi vừa kiểm tra câu trả lời của Artley. Tôi sẽ chăm sóc điều này vào lần tới.
Sanchit Gupta

17

Không có giải pháp sẵn có cho vấn đề này, đây là một vấn đề với thiết kế và mẫu mã của bạn.

Bạn có thể sử dụng mẫu nhà xuất bản / thuê bao. Đối với điều này, bạn có thể sử dụng các sự kiện tùy chỉnh jQuery hoặc cơ chế sự kiện của riêng bạn.

Đầu tiên,

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

Bây giờ bạn có thể đăng ký các sự kiện divhtmlchanging / divhtmlchanged như sau,

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

Bây giờ, bạn phải thay đổi nội dung div thay đổi thông qua changeHtml()chức năng này . Vì vậy, bạn có thể theo dõi hoặc có thể thực hiện các thay đổi cần thiết cho phù hợp vì liên kết đối số dữ liệu gọi lại có chứa thông tin.

Bạn phải thay đổi html của div như thế này;

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

Ngoài ra, bạn có thể sử dụng điều này cho bất kỳ (các) phần tử html nào ngoại trừ phần tử đầu vào. Dù sao, bạn có thể sửa đổi điều này để sử dụng với bất kỳ yếu tố nào.


Để quan sát và hành động thay đổi đối với một yếu tố cụ thể, chỉ cần sửa đổi hàm changeHtml để sử dụng 'elem.trigger (...)' thay vì 'jQuery.event.trigger (...)', sau đó liên kết với thành phần như $ ('# my_element_id'). on ('htmlchanged', hàm (e, dữ liệu) {...}
KenB

8
"Đây là một vấn đề với thiết kế và mẫu mã của bạn", phải làm gì nếu bạn bao gồm các tập lệnh của bên thứ ba do đó bạn không kiểm soát được mã nguồn của họ? Nhưng bạn cần phát hiện những thay đổi của họ đối với một div?
DrLightman

@DrLightman một nguyên tắc nhỏ là chọn lib của bên thứ ba với sự kiện gọi lại được cung cấp
Marcel Djaman

8

Sử dụng M mutObserver như đã thấy trong đoạn trích này do Mozilla cung cấp và được điều chỉnh từ bài đăng trên blog này

Ngoài ra, bạn có thể sử dụng ví dụ JQuery được thấy trong liên kết này

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

Bạn có thể lưu trữ InternalHTML cũ của div trong một biến. Đặt một khoảng để kiểm tra xem nội dung cũ có khớp với nội dung hiện tại không. Khi điều này không đúng, hãy làm gì đó.


1

Hãy dùng thử M mutObserver:

hỗ trợ trình duyệt: http://caniuse.com/#feat=mutingobserver

<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

Thêm một số nội dung vào div, cho dù thông qua jQuery hoặc qua de DOM-API, mặc định cho .appendChild()hàm. Những gì bạn có thể làm là ghi đè .appendChild()chức năng của đối tượng hiện tại và thực hiện một trình quan sát trong đó. Bây giờ đã ghi đè .appendChild()chức năng của chúng tôi , chúng tôi cần mượn chức năng đó từ một đối tượng khác để có thể nối thêm nội dung. Do đó, chúng tôi gọi .appendChild()một div khác để cuối cùng nối thêm nội dung. Tất nhiên, điều này cũng được tính cho .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);
        }
    };

Ở đây bạn có thể tìm thấy một ví dụ naïf. Bạn có thể mở rộng nó một mình tôi đoán. http://jsfiddle.net/RKLmA/31/

Nhân tiện: điều này cho thấy JavaScript tuân thủ nguyên tắc OpenCloses. :)


Nó không hoạt động với append con ... Tôi thực sự sửa đổi html của nó thông qua các chức năng khác.
BoqBoq

Giống như removeChild () thayChild (), v.v. Nhưng bạn đã đúng trong InternalHTML. Bạn nên tránh nó bằng cách nào đó.
Andries
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.