Чи є слухач змін у JavaScript / jQuery DOM?


402

По суті, я хочу, щоб сценарій виконувався при DIVзміні вмісту . Оскільки сценарії є окремими (скрипт вмісту в сценарії розширення та веб-сторінки Chrome), мені потрібен спосіб просто спостерігати за змінами в стані DOM. Я міг би встановити опитування, але це здається неохайним.

Відповіді:


488

Протягом тривалого часу події мутації DOM3 були найкращим доступним рішенням, але вони були застарілі з міркувань продуктивності. Спостерігачі мутації DOM4 є заміною для застарілих подій мутації DOM3. Вони в даний час реалізовані в сучасних браузерах , як 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цілому піддіреві, і він запускатиме зміни в атрибутах елементів, а також структурні зміни. У проекті специфікації є повний перелік дійсних властивостей слухача мутацій :

список дітей

  • Встановіть, trueчи слід спостерігати мутації для дітей, націлених на них.

атрибути

  • Встановіть, trueчи слід спостерігати мутації атрибутів цілі.

характерДані

  • Встановіть, trueчи слід спостерігати мутації даних даних.

піддерево

  • Встановіть, trueчи слід спостерігати мутації не лише націлених, але й нащадків цілі.

attributeOldValue

  • Встановіть, trueякщо attributesвстановлено значення true та атрибута target перед тим, як мутація повинна бути записана.

символDataOldValue

  • Установіть, trueчи characterDataвстановлено значення true та даних цілі, перш ніж мутація повинна бути записана.

attributeFilter

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

(Цей список є поточним станом на квітень 2014 року; ви можете перевірити специфікацію на наявність будь-яких змін.)


3
@AshrafBashir Я бачу, що зразок працює добре у Firefox 19.0.2: я бачу ([{}])ввійшов до консолі, який показує очікуване, MutationRecordколи я натискаю на неї. Перевірте ще раз, оскільки це могло бути тимчасовою технічною несправністю в JSFiddle. Я ще не тестував його в IE, оскільки у мене немає IE 10, який наразі є єдиною версією, яка підтримує мутаційні події.
апспіллери

1
Я щойно опублікував відповідь, яка працює в IE10 + і в основному все інше.
naugtur

1
У специфікації, здається, немає зеленого поля, в якому більше не відображаються параметри спостерігача за мутацією. Він перераховує параметри в розділі 5.3.1 і описує їх трохи нижче цього.
LS

2
@LS Дякую, я оновив посилання, видалив трохи про зелене поле і відредагував увесь список у своїй відповіді (про всяк випадок майбутньої гнилі посилання).
апспіллери


211

Редагувати

Зараз ця відповідь застаріла. Дивіться відповідь апсилерів .

Оскільки це розширення для Chrome, ви можете також використовувати стандартний захід DOM - DOMSubtreeModified. Дивіться підтримку цієї події у веб-переглядачах. Він підтримується в Chrome з 1.0.

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

Дивіться робочий приклад тут .


Я помітив, що цю подію можна звільнити навіть після певних селекторів. Зараз я розслідую.
Педер Райс

9
w3.org/TR/DOM-Level-3-Events/#event-type-DOMSubtreeModified говорить, що ця подія застаріла, що б ми використали замість цього?
Маслоу

2
@ Маслоу - Немає! stackoverflow.com/questions/6659662 / ...
Sam Rueby

4
Існує github.com/joelpurra/jquery-mutation-summary, який в основному вирішує його для користувачів jquery.
Capi Etheriel

1
Все ще працює, якщо ви будуєте хромовані розширення. неоціненний.
концепція47

49

Багато сайтів використовують AJAX для динамічного додавання / показу / зміни вмісту. Іноді використовується замість навігації на сайті, тому поточна URL-адреса змінюється програмно, а скрипт вмісту в цьому випадку браузер не виконується автоматично, оскільки сторінка не завантажується повністю з віддаленого сервера.


Звичайні методи JS виявлення змін сторінок, доступних у контентному скрипті .


Спеціальні розширення: виявляють зміни URL-адреси на тлі фону / події .

Існує розширений API для роботи з навігацією: webNavigation , webRequest , але ми будемо використовувати простий chrome.tabs.onUp updated слухач подій, який надсилає повідомлення до сценарію вмісту:

  • manifest.json:
    оголосити фон / сторінку події
    оголосити скрипт вмісту
    додати "tabs" дозвіл .

  • background.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

Ще один підхід залежно від того, як ви змінюєте діву. Якщо ви використовуєте 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.


7

На додаток до "сировинних" інструментів, наданих MutationObserverAPI , існують "зручні" бібліотеки для роботи з мутаціями 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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.