jQuery подія: виявляє зміни до html / тексту діла


265

У мене є DIV , який має свій зміст весь час змінюється, будь то ajax requests, jquery functions, і blurт.д. і т.п.

Чи є спосіб я виявити будь-які зміни в своєму діві в будь-який момент часу?

Я не хочу використовувати перевірені інтервали або значення за замовчуванням.

Щось подібне зробило б

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

5
Можливий дублікат: stackoverflow.com/questions/10328102/…
Роб

14
@Rob Це пов'язує keypressподію для змістовного <div>елемента. Я не впевнений, що рішення стосуються цього. Вони, безумовно, не сприймають програмних змін до змісту елемента.
Ентоні Грист

Відповіді:


407

Якщо ви не хочете використовувати таймер і перевірити внутрішній HTML, ви можете спробувати цю подію

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

Детальніше та дані про підтримку веб-переглядача - тут .

Увага: у новіших версіях jQuery bind () застаріле, тому замість цього слід використовувати на ():

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

14
Майте на увазі, що DOMSubtreeModified не підтримується в IE8 (і нижче).
Гавін


3
Mozilla 33: випав при рекурсії для елемента <body>. Потрібно знайти інший спосіб
Chaki_Black

17
Це серйозно НЕ використовуйте цю подію, вона призведе до краху всієї вашої роботи, оскільки вона звільняється весь час. Замість цього використовуйте події нижче $ ('. MyDiv'). Bind ('DOMNodeInserted DOMNodeRemoved', function () {});
Джордж СЕДРА

19
Цей метод застарілий! Замість цього використовуйте:$("body").on('DOMSubtreeModified', "mydiv", function() { });
Асиф

55

Використання Javascript MutationObserver

  //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
Це правильна відповідь, оскільки зараз це надається перевазі використання DOMSubtreeModified
Джоела Деві

3
Я отримую помилку з цим, навіть якщо я дав правильний вибір. "VM21504: 819 Uncaught TypeError: Не вдалося виконати" спостерігати "на" MutationObserver ": параметр 1 не типу" Вузол "."
Самір


42

Ви можете спробувати це

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

});

але це може не працювати в Internet Explorer, не перевіряли його



3
ПРИМІТКА!: Якщо ви використовуєте це для тригера і на сторінці вноситься багато змін - він запустить вашу функцію X разів (можливо, навіть X = 1000 і більше), що може бути дуже неефективно. Одне просте рішення - визначити "запущений" булевий var, який буде ... якщо (працює == true) {return} ... без запуску коду, якщо він вже працює. Встановіть run = true прямо після вашої логіки, а run = false перед виходом функції. Ви також можете використовувати таймер, щоб обмежити свою функцію лише тим, що зможете виконувати кожні X секунд. біг = правда; setTimeout (function () {running = false}, 5000); (або щось краще)
JxAxMxIxN

Я використовував це у вікні вибору, у якому були додані та видалені параметри. Він працював чудово, коли елементи були додані, але видалення здавалося, що на 1 елемент позаду. Коли останній варіант було видалено, він не запустився.
CodeMonkey

2
@JxAxMxIxN Ви також можете збільшити таймер таймауту, очистивши та встановивши тайм-аут знову:clearTimeout(window.something); window.something = setTimeout(...);
Ctrl-C

домовились - ваш шлях - шлях - з моменту вивчення Python я очистив багато моїх поганих методів кодування на декількох мовах (не всі, просто багато;)
JxAxMxIxN

33

Ви шукаєте MutationObserver або Mutation Events . Ніхто не підтримується скрізь, а світ розробника не надто прихильно сприймається.

Якщо ви знаєте (і можете переконатися, що) розмір div зміниться, можливо, ви зможете використовувати подію зміни розміру крос-браузера .


1
Це одне. Зокрема, DOMSubtreeModified . Вам може бути корисна бібліотека з підсумками мутацій , і цей список подій дерева DOM .
BenjaminRH


9
Якщо будь-хто інший повинен був спробувати прочитати все скрізь, це правильна відповідь. Події мутації підтримувались у попередніх браузерах, Mutation Observer - це те, що буде підтримуватися в сучасних браузерах, і воно буде підтримуватися в майбутньому. Дивіться посилання для підтримки: спостерігач за мутацією CANIUSE
Josh Mc

20

Наступний код працює для мене.

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

Сподіваюся, це комусь допоможе :)


Це та сама відповідь, що і відповідь від @Artley
Чорний

@Black Спасибі! Я тільки перевірив відповідь Артлі. Я подбаю про це наступного разу.
Санчіт Гупта

17

Вбудованого рішення цієї проблеми немає, це проблема з вашим дизайном та кодуванням.

Ви можете використовувати шаблон видавця / підписника. Для цього ви можете використовувати власні події jQuery або власний механізм подій.

Перший,

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

Тепер ви можете підписатися на події divhtmlchanging / divhtmlchanged наступним чином,

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

Тепер ви повинні змінити зміни вмісту Div через цю changeHtml()функцію. Отже, ви можете відстежувати або вносити необхідні зміни відповідно, оскільки прив'язує аргумент даних зворотного виклику, що містить інформацію.

Ви повинні змінити HTML свого div, як це;

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

Крім того, ви можете використовувати це для будь-яких html-елементів, крім елемента введення. У будь-якому випадку ви можете змінити це для використання з будь-якими елементами.


Щоб спостерігати і діяти над змінами певного елемента, просто змініть функцію changeHtml, щоб використовувати 'elem.trigger (...)' замість 'jQuery.event.trigger (...)', а потім прив’язати до елемента, як $ ('# my_element_id'). on ('htmlchanged', функція (e, дані) {...}
KenB

8
"це проблема з вашим шаблоном дизайну та кодування", що робити, якщо ви включаєте сторонні сценарії, тому у вас немає контролю над їх вихідним кодом? але вам потрібно виявити їх зміни в одному діві?
DrLightman

@DrLightman правилом є вибір сторонніх ліб з можливістю зворотного виклику
Marcel Djaman

8

Використовуйте MutationObserver, як показано в цьому фрагменті, наданому Mozilla та адаптованому з цього допису в блозі

Крім того, ви можете використовувати приклад JQuery, який бачите в цьому посиланні

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

Ви можете зберігати старий InternalHTML div в змінній. Встановіть інтервал, щоб перевірити, чи відповідає старий вміст поточному вмісту. Коли це неправда, роби щось.


1

Спробуйте MutationObserver:

підтримка браузера: http://caniuse.com/#feat=mutationobserver

<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

Додавання деякого вмісту до div, чи через jQuery, або через de DOM-API безпосередньо, за замовчуванням .appendChild()функція. Що ви можете зробити, це перекрити .appendChild()функцію поточного об'єкта та запровадити в ньому спостерігач. Тепер, скасувавши нашу .appendChild()функцію, нам потрібно запозичити цю функцію у іншого об’єкта, щоб мати змогу додавати вміст. Для цього ми закликаємо .appendChild()інший div, щоб остаточно додати вміст. Звичайно, це враховується і для .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);
        }
    };

Тут ви можете знайти наївний приклад. Ви можете продовжити його самостійно, мабуть. http://jsfiddle.net/RKLmA/31/

До речі: це показує, що JavaScript відповідає принципу OpenClosed. :)


Це не працює з додаванням дитини ... Я фактично змінюю html його за допомогою інших функцій.
BoqBoq

Як і видалити deleteChild () Вам слід якось уникати цього.
Андріс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.