Có trình nghe thay đổi JavaScript / jQuery DOM không?


402

Về cơ bản tôi muốn có một kịch bản thực thi khi nội dung của một DIVthay đổi. Vì các tập lệnh là riêng biệt (tập lệnh nội dung trong tập lệnh mở rộng & trang web của Chrome), tôi cần một cách đơn giản là quan sát các thay đổi trong trạng thái DOM. Tôi có thể thiết lập bỏ phiếu nhưng điều đó có vẻ cẩu thả.

Câu trả lời:


488

Trong một thời gian dài, các sự kiện đột biến DOM3 là giải pháp khả dụng tốt nhất, nhưng chúng đã bị phản đối vì lý do hiệu suất. Trình quan sát đột biến DOM4 là sự thay thế cho các sự kiện đột biến DOM3 không được chấp nhận. Chúng hiện được triển khai trong các trình duyệt hiện đại dưới dạng MutationObserver(hoặc là tiền tố của nhà cung cấp WebKitMutationObservertrong các phiên bản cũ của Chrome):

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations, observer) {
    // fired when a mutation occurs
    console.log(mutations, observer);
    // ...
});

// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
  subtree: true,
  attributes: true
  //...
});

Ví dụ này lắng nghe các thay đổi DOM trên documentvà toàn bộ cây con của nó và nó sẽ kích hoạt các thay đổi đối với các thuộc tính thành phần cũng như các thay đổi về cấu trúc. Thông số kỹ thuật dự thảo có một danh sách đầy đủ các thuộc tính người nghe đột biến hợp lệ :

danh sách con

  • Đặt thành truenếu đột biến cho trẻ em của mục tiêu sẽ được quan sát.

thuộc tính

  • Đặt thành truenếu đột biến thành thuộc tính của mục tiêu sẽ được quan sát.

nhân vậtData

  • Đặt thành truenếu đột biến dữ liệu của mục tiêu sẽ được quan sát.

cây con

  • Đặt thành truenếu đột biến không chỉ nhắm mục tiêu, mà cả con cháu của mục tiêu sẽ được quan sát.

propertyOldValue

  • Đặt thành truenếu attributesđược đặt thành đúng và giá trị thuộc tính của mục tiêu trước khi đột biến cần được ghi lại.

nhân vậtDataOldValue

  • Đặt thành truenếu characterDatađược đặt thành đúng và dữ liệu của mục tiêu trước khi đột biến cần được ghi lại.

bộ lọc thuộc tính

  • Đặt thành một danh sách các tên cục bộ thuộc tính (không có không gian tên) nếu không phải quan sát tất cả các đột biến thuộc tính.

(Danh sách này là hiện tại kể từ tháng 4 năm 2014; bạn có thể kiểm tra thông số kỹ thuật cho bất kỳ thay đổi nào.)


3
@AshrafBashir Tôi thấy mẫu hoạt động tốt trong Firefox 19.0.2: Tôi thấy ([{}])đã đăng nhập vào bảng điều khiển, hiển thị mong đợi MutationRecordkhi tôi nhấp vào nó. Vui lòng kiểm tra lại, vì nó có thể là một lỗi kỹ thuật tạm thời trong JSFiddle. Tôi chưa thử nghiệm nó trong IE, vì tôi không có IE 10, hiện là phiên bản duy nhất hỗ trợ các sự kiện đột biến.
apsillers

1
Tôi vừa đăng một câu trả lời hoạt động trong IE10 + và hầu hết mọi thứ khác.
khai mạc

1
Thông số kỹ thuật dường như không có hộp màu xanh liệt kê các tùy chọn quan sát đột biến nữa. Nó liệt kê các tùy chọn trong phần 5.3.1 và mô tả chúng chỉ một chút nữa bên dưới.
LS

2
@LS Cảm ơn, tôi đã cập nhật liên kết, xóa bit về hộp màu xanh lá cây và chỉnh sửa toàn bộ danh sách vào câu trả lời của tôi (chỉ trong trường hợp bị thối liên kết trong tương lai).
apsillers

3
Đây là bảng tương thích trình duyệt từ Tôi có thể sử dụng.
bdesham

211

Biên tập

Câu trả lời này hiện không được chấp nhận. Xem câu trả lời của apsillers .

Vì đây là phần mở rộng của Chrome, bạn cũng có thể sử dụng sự kiện DOM tiêu chuẩn - DOMSubtreeModified. Xem hỗ trợ cho sự kiện này trên các trình duyệt. Nó đã được hỗ trợ trong Chrome kể từ 1.0.

$("#someDiv").bind("DOMSubtreeModified", function() {
    alert("tree changed");
});

Xem một ví dụ làm việc ở đây .


Tôi đã nhận thấy rằng sự kiện này có thể được kích hoạt ngay cả sau khi một số bộ chọn nhất định. Tôi hiện đang điều tra.
Gạo Peder

9
w3.org/TR/DOM-Level-3-Events/#event-type-DOMSubtreeModified nói rằng sự kiện này không được chấp nhận, thay vào đó chúng ta sẽ sử dụng cái gì?
Maslow


4
github.com/joelpurra/jquery-muting-summary về cơ bản giải quyết nó cho người dùng jquery.
Capi Etheriel

1
Vẫn hoạt động nếu bạn đang xây dựng tiện ích mở rộng chrome. vô giá
khái niệm47

49

Nhiều trang web sử dụng AJAX để thêm / hiển thị / thay đổi nội dung một cách linh hoạt. Đôi khi, nó được sử dụng thay vì điều hướng trong trang web, vì vậy URL hiện tại được thay đổi theo chương trình và tập lệnh nội dung không được trình duyệt tự động thực hiện trong trường hợp này do trang không được tải hoàn toàn từ máy chủ từ xa.


Các phương thức JS thông thường để phát hiện các thay đổi trang có sẵn trong một tập lệnh nội dung .

  • M mutObserver ( docs ) để phát hiện các thay đổi DOM theo nghĩa đen:

  • Trình nghe sự kiện cho các trang web báo hiệu nội dung thay đổi bằng cách gửi sự kiện DOM:

  • Kiểm tra định kỳ DOM thông qua setInterval :
    Rõ ràng điều này sẽ chỉ hoạt động trong trường hợp khi bạn chờ đợi một phần tử cụ thể được xác định bởi id / bộ chọn của nó xuất hiện và nó sẽ không cho phép bạn phát hiện nội dung mới được thêm động trừ khi bạn phát minh ra một loại dấu vân tay các nội dung hiện có.

  • API lịch sử che giấu bên trong tập lệnh DOM được tiêm :

    document.head.appendChild(document.createElement('script')).text = '(' +
        function() {
            // injected DOM script is not a content script anymore, 
            // it can modify objects and functions of the page
            var _pushState = history.pushState;
            history.pushState = function(state, title, url) {
                _pushState.call(this, state, title, url);
                window.dispatchEvent(new CustomEvent('state-changed', {detail: state}));
            };
            // repeat the above for replaceState too
        } + ')(); this.remove();'; // remove the DOM script element
    
    // And here content script listens to our DOM script custom events
    window.addEventListener('state-changed', function(e) {
        console.log('History state changed', e.detail, location.hash);
        doSomething();
    });
  • Nghe băm , sự kiện popstate :

    window.addEventListener('hashchange', function(e) {
        console.log('URL hash changed', e);
        doSomething();
    });
    window.addEventListener('popstate', function(e) {
        console.log('State changed', e);
        doSomething();
    });



Cụ thể về tiện ích mở rộng: phát hiện các thay đổi URL trong trang nền / sự kiện .

Có API nâng cao để hoạt động với điều hướng: webNavulation , webRequest , nhưng chúng tôi sẽ sử dụng trình nghe sự kiện chrome.tabs.onUpdated đơn giản để gửi tin nhắn đến tập lệnh nội dung:

  • manifest.json:
    khai báo trang nền / sự kiện
    khai báo tập lệnh nội dung
    thêm "tabs" quyền .

  • nền.js

    var rxLookfor = /^https?:\/\/(www\.)?google\.(com|\w\w(\.\w\w)?)\/.*?[?#&]q=/;
    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
        if (rxLookfor.test(changeInfo.url)) {
            chrome.tabs.sendMessage(tabId, 'url-update');
        }
    });
  • content.js

    chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
        if (msg === 'url-update') {
            doSomething();
        }
    });

29

Một cách tiếp cận khác tùy thuộc vào cách bạn thay đổi div. Nếu bạn đang sử dụng JQuery để thay đổi nội dung của div bằng phương thức html (), bạn có thể mở rộng phương thức đó và gọi hàm đăng ký mỗi khi bạn đặt html vào div.

(function( $, oldHtmlMethod ){
    // Override the core html method in the jQuery object.
    $.fn.html = function(){
        // Execute the original HTML method using the
        // augmented arguments collection.

        var results = oldHtmlMethod.apply( this, arguments );
        com.invisibility.elements.findAndRegisterElements(this);
        return results;

    };
})( jQuery, jQuery.fn.html );

Chúng tôi chỉ chặn các cuộc gọi đến html (), gọi hàm đăng ký bằng hàm này, trong ngữ cảnh đề cập đến phần tử đích nhận nội dung mới, sau đó chúng tôi chuyển cuộc gọi đến hàm jquery.html () ban đầu. Hãy nhớ trả về kết quả của phương thức html () ban đầu, bởi vì JQuery mong đợi nó cho chuỗi phương thức.

Để biết thêm thông tin về ghi đè phương thức và tiện ích mở rộng, hãy xem http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Argument-To-Override-Core-jQuery-Methods.htm , đó là nơi Tôi nôi chức năng đóng cửa. Ngoài ra, hãy xem hướng dẫn bổ trợ tại trang web của JQuery.


7

Ngoài các công cụ "thô" do MutationObserverAPI cung cấp , còn tồn tại các thư viện "tiện lợi" để làm việc với các đột biến DOM.

Xem xét: M mutObserver đại diện cho mỗi thay đổi DOM về mặt cây con. Vì vậy, nếu bạn đang chờ đợi một yếu tố nào đó được chèn vào, nó có thể nằm sâu bên trong trẻ em mutations.mutation[i].addedNodes[j].

Một vấn đề khác là khi mã của riêng bạn, phản ứng với các đột biến, thay đổi DOM - bạn thường muốn lọc nó ra.

Một thư viện tiện lợi tốt giải quyết các vấn đề như vậy là mutation-summary(từ chối trách nhiệm: Tôi không phải là tác giả, chỉ là người dùng hài lòng), cho phép bạn chỉ định các truy vấn về những gì bạn quan tâm và có được chính xác điều đó.

Ví dụ sử dụng cơ bản từ các tài liệu:

var observer = new MutationSummary({
  callback: updateWidgets,
  queries: [{
    element: '[data-widget]'
  }]
});

function updateWidgets(summaries) {
  var widgetSummary = summaries[0];
  widgetSummary.added.forEach(buildNewWidget);
  widgetSummary.removed.forEach(cleanupExistingWidget);
}
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.