Is there a JavaScript/jQuery DOM change listener?

Essentially I want to have a script execute when the contents of a DIV change. Since the scripts are separate (content script in chrome extension & webpage script), I need a way simply observe changes in DOM state. I could set up polling but that seems sloppy.


The old contents of this answer is now deprecated.
See the other answers based on MutationObserver .


Several years later, there is now officially a better solution. DOM4 Mutation Observers are the replacement for deprecated DOM3 mutation events. They are currently implemented in modern browsers as MutationObserver (or as the vendor-prefixed WebKitMutationObserver in old versions of 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
  //...
});

This example listens for DOM changes on document and its entire subtree, and it will fire on changes to element attributes as well as structural changes. The draft spec has a full list of valid mutation listener properties:

childList

  • Set to true if mutations to target's children are to be observed.
  • attributes

  • Set to true if mutations to target's attributes are to be observed.
  • characterData

  • Set to true if mutations to target's data are to be observed.
  • subtree

  • Set to true if mutations to not just target, but also target's descendants are to be observed.
  • attributeOldValue

  • Set to true if attributes is set to true and target's attribute value before the mutation needs to be recorded.
  • characterDataOldValue

  • Set to true if characterData is set to true and target's data before the mutation needs to be recorded.
  • attributeFilter

  • Set to a list of attribute local names (without namespace) if not all attribute mutations need to be observed.
  • (This list is current as of April 2014; you may check the specification for any changes.)


    Many sites use AJAX to add/show/change content dynamically. Sometimes it's used instead of in-site navigation, so current URL is changed programmatically and content scripts aren't automatically executed by browser in this case since the page isn't fetched from remote server entirely.


    Usual JS methods of detecting page changes available in a content script.

  • MutationObserver (docs) to literally detect DOM changes:

  • How to change the HTML content as it's loading on the page
  • Performance of MutationObserver to detect nodes in entire DOM.
  • Event listener for sites that signal content change by sending a DOM event:

  • pjax:end on document used by many pjax-based sites eg GitHub,
    see How to run jQuery before and after a pjax load?
  • message on window used by eg Google search in Chrome browser,
    see Chrome extension detect Google search refresh
  • spfdone on document used by Youtube,
    see How to detect page navigation on Youtube and modify HTML before page is rendered?
  • Periodic checking of DOM via setInterval :
    Obviously this will work only in cases when you wait for a specific element identified by its id/selector to appear, and it won't let you universally detect new dynamically added content unless you invent some kind of fingerprinting the existing contents.

  • Cloaking History API inside an injected DOM script:

    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();
    });
    
  • Listening to hashchange, popstate events:

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



  • Extensions-specific: detect URL changes in a background / event page.

    There are advanced API to work with navigation: webNavigation, webRequest, but we'll use simple chrome.tabs.onUpdated event listener that sends a message to the content script:

  • manifest.json:
    declare background/event page
    declare content script
    add "tabs" permission.

  • background.js

    var rxLookfor = /^https?://(www.)?google.(com|ww(.ww)?)/.*?[?#&]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();
        }
    });
    
  • 链接地址: http://www.djcxy.com/p/91128.html

    上一篇: 如何保存Chrome开发人员工具的样式面板的CSS更改?

    下一篇: 是否有JavaScript / jQuery DOM更改侦听器?