Есть ли прослушиватель изменений JavaScript/jQuery DOM?

по сути, я хочу, чтобы скрипт выполнялся при изменении содержимого DIV. Поскольку скрипты разделены (сценарий содержимого в chrome extension & Webpage script), мне нужен способ просто наблюдать за изменениями в состоянии DOM. Я мог бы организовать опрос, но это кажется небрежным.

5 ответов


несколько лет спустя, теперь официально есть лучшее решение. наблюдатели мутаций DOM4 являются заменой устаревших событий мутации DOM3. Они в настоящее время реализован в современных браузерах as MutationObserver (или как поставщик-префикс WebKitMutationObserver в старых версиях 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
  //...
});

этот пример прослушивает изменения DOM на document и все его поддерево, и он будет стрелять по изменениям атрибутов элементов, а также структурных изменения. Проект спецификации имеет полный список действительных свойства прослушивателя мутаций:

childList

  • значение true если будут наблюдаться мутации для детей цели.

атрибуты

  • значение true если будут наблюдаться мутации атрибутов target.

characterData

  • значение true если будут наблюдаться мутации данных target.

поддерева

  • значение true если будут наблюдаться мутации не только для цели, но и для потомков цели.

attributeOldValue

  • значение true если attributes имеет значение true и значение атрибута target до того, как мутация должна быть записана.

characterDataOldValue

  • значение true если characterData имеет значение true и данные цели до того, как мутация должна быть записана.

attributeFilter

  • задайте список локальных имен атрибутов (без пространства имен), если необходимо наблюдать не все мутации атрибутов.

(этот список является текущим по состоянию на апрель 2014 года; вы можете проверить спецификация для любых изменений.)


редактировать

этот ответ теперь устарел. Просмотреть ответ apsillers.

поскольку это для расширения Chrome, вы можете также использовать стандартное событие DOM -DOMSubtreeModified. См. поддержку для этого событие в разных браузерах. Он поддерживается в Chrome с 1.0.

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

см. рабочий пример здесь.


многие сайты используют AJAX для динамического добавления/отображения/изменения содержимого. Иногда он используется вместо навигации на сайте, поэтому текущий URL-адрес изменяется программно, а сценарии содержимого не выполняются автоматически браузером в этом случае, поскольку страница не извлекается с удаленного сервера полностью.


обычные методы JS обнаружения изменений страницы, доступные в скрипт контент.


расширения: обнаружение изменений URL в фон / страница событие.

есть расширенный API для работы с оборудованием: webNavigation, webRequest, но мы будем использовать простой chrome.вешалки.onUpdated прослушиватель событий, который отправляет скрипт содержанием:

  • манифест.в JSON:
    объявить фон / страница событий
    объявить скрипт контент
    добавить "tabs" разрешение.

  • фон.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');
        }
    });
    
  • содержание.js

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

другой подход в зависимости от того, как вы меняете разд. Если вы используете JQuery для изменения содержимого div с помощью метода html (), вы можете расширить этот метод и вызвать функцию регистрации каждый раз, когда вы помещаете html в 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 );

мы просто перехватываем вызовы html (), вызываем функцию регистрации с этим, которая в контексте ссылается на целевой элемент, получающий новое содержимое, затем мы передаем вызов исходному jquery.функция html (). Не забудьте верните результаты исходного метода html (), потому что JQuery ожидает его для цепочки методов.

для получения дополнительной информации о переопределении и расширении метода проверьте http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm, в котором я заложил функцию закрытия. Также ознакомьтесь с учебником плагинов на сайте JQuery.


в дополнение к "сырым" инструментам, предоставляемым MutationObserver API, существуют библиотеки "удобства" для работы с мутациями DOM.

считаем: mutationobserver'а представляет каждого изменения DOM в плане поддеревьев. Поэтому, если вы, например, ждете, пока будет вставлен определенный элемент, он может быть глубоко внутри детей mutations.mutation[i].addedNodes[j].

другая проблема заключается в том, когда ваш собственный код, в ответ на мутации, изменяет DOM-вы часто хотите отфильтровать его из.

хорошая библиотека удобства которая разрешает такие проблемы mutation-summary (отказ от ответственности: я не автор, просто довольный пользователь), что позволяет вам указывать запросы того, что вас интересует, и получать именно это.

основной пример использования из документов:

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