Обнаружение изменений содержимого элемента с помощью jQuery

113

change() функция работает и обнаруживает изменения в элементах формы, но есть ли способ определить, когда содержимое элемента DOM было изменено?

Это не работает, если только #contentэто не элемент формы

$("#content").change( function(){
    // do something
});

Я хочу, чтобы это срабатывало при выполнении чего-то вроде:

$("#content").html('something');

Также html()или у append()функции нет обратного вызова.

Какие-либо предложения?

Эльзо Валуги
источник
старый вопрос, который я знаю, но проверьте мой ответ на предмет элегантного решения stackoverflow.com/a/23826615/744975
Эндрю Аткинсон

Ответы:

26

Это события мутации .

Я не использовал API-интерфейсы событий мутаций в jQuery, но беглый поиск привел меня к этому проекту на GitHub. Я не знаю о зрелости проекта.

Джархатх
источник
17
Этот плагин событий мутации не будет работать, потому что он просто перехватывает события в методы мутации jQuery. Они запускаются, когда сам jQuery пытается изменить элементы, но не когда элементы изменяются извне jQuery. Они не следят за изменениями в документе.
Попробуйте
10
Поиск в Google и размещение ссылки на библиотеку, которую вы никогда не пробовали, не очень полезны. (Комментируя, потому что меня побудили к голосованию против.)
Хватит клеветать на Монику Челлио
27
События мутации устарели ; не используйте их.
Брок Адамс,
Альтернативой мутационным событиям кажутся MutationObservers .
WoodrowShigeru
69

Я знаю, что этому посту год, но я хотел бы предложить другой подход к решению тем, у кого есть аналогичная проблема:

  1. Событие изменения jQuery используется только в полях ввода пользователя, потому что, если манипулируют чем-то еще (например, div), эта манипуляция исходит из кода. Итак, найдите, где происходит манипуляция, а затем добавьте туда все, что вам нужно.

  2. Но если это невозможно по какой-либо причине (вы используете сложный плагин или не можете найти возможности «обратного вызова»), то подход jQuery, который я предлагаю, выглядит следующим образом:

    а. Для простых манипуляций с DOM используйте jQuery chaining and traversing,$("#content").html('something').end().find(whatever)....

    б. Если вы хотите сделать что-то еще, используйте jQuery bindс настраиваемым событием иtriggerHandler

    $("#content").html('something').triggerHandler('customAction');
    
    $('#content').unbind().bind('customAction', function(event, data) {
       //Custom-action
    });
    

Вот ссылка на обработчик триггера jQuery: http://api.jquery.com/triggerHandler/

Кайл
источник
1
последняя мысль. хотя выше это должно быть довольно исчерпывающим: вы можете обновить значение скрытого поля ввода значением #content html, а затем привязать событие изменения к скрытому полю ввода :) множество вариантов
Кайл,
7
+1 «Найдите, где происходит манипуляция, а затем добавьте туда все, что вам нужно». Исправлена ​​моя проблема за 2 секунды без каких-либо хаков / плагинов :)
Хартли Броуди
Единственное изменение, которое я предлагаю здесь, - это то, что bindожидает, что ваш обработчик вернет файл bool.
Серж Саган
15

Браузер не будет запускать событие onchange для <div>элементов.

Я думаю, что причина этого в том, что эти элементы не изменятся, если не будут изменены с помощью javascript. Если вам уже нужно изменить элемент самостоятельно (а не сам пользователь), вы можете просто вызвать соответствующий сопутствующий код одновременно с изменением элемента, например:

 $("#content").html('something').each(function() { });

Вы также можете вручную запустить событие, подобное этому:

 $("#content").html('something').change();

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

TM.
источник
11
Это предполагает, что вы написали весь javascript, что может быть не так.
Myster
СПАСИБО!!!! Это просто помогло мне решить проблему, на которую я смотрел 6 часов.
Jordan Parmer
Именно то, что мне нужно.
smac89
15

как насчет http://jsbin.com/esepal/2

$(document).bind("DOMSubtreeModified",function(){
  console.log($('body').width() + ' x '+$('body').height());
})

Это событие устарело и заменено на Mutation Observer API.

FDisk
источник
1
неплохая идея, хотя интересно, сколько у нее поддержки. developer.mozilla.org/en/DOM/DOM_event_reference/…
Эльзо Валуги
Как вы отслеживаете изменения в конкретном элементе? В настоящее время документ контролирует всю страницу.
Patoshi パ ト シ
3

Это не совсем ответ jQuery, но его полезно упомянуть для отладки.

В Firebug вы можете щелкнуть правой кнопкой мыши элемент в дереве DOM и настроить «Прерывание при изменении атрибута»:

Щелкните правой кнопкой мыши элемент в Firebug с выделенным прерыванием при изменении атрибута

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

Джон Рид
источник
1
Это полезно, но не совсем то, о чем он просил. Это будет обнаруживать такие вещи, как изменение класса, добавление или изменение атрибута стиля. Он не будет проверять, когда изменяется содержимое внутри узла. Например, если какой-то javascript где-то изменит узел с <span> hello </span> на <span> World </span>, он не обнаружит его,
Джошуа Сойло,
2

Я разрабатываю крошечную библиотеку JS под названием mutabor ( https://github.com/eskat0n/mutabor ), которая предназначена для упрощения использования событий мутации DOM. См. Примеры на demo.html.

Eskat0n
источник
1

Часто простой и эффективный способ добиться этого - отслеживать, когда и где вы изменяете DOM.

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

В недавнем приложении мне не требовались немедленные действия, поэтому я использовал обратный вызов для функции handly load (), чтобы добавить класс к любым измененным элементам, а затем обновлять все измененные элементы каждые несколько секунд с помощью таймера setInterval.

$($location).load("my URL", "", $location.addClass("dommodified"));

Тогда вы можете справиться с этим, как хотите - например,

setInterval("handlemodifiedstuff();", 3000); 
function handlemodifiedstuff()
{
    $(".dommodified").each(function(){/* Do stuff with $(this) */});
}
Энтони Карти
источник
3
Это предполагает, что вы написали весь javascript, что может быть не так.
Myster
1

Вы можете добавить опцию обратного вызова к функции html (или любой другой):

$.fn.oldHtml = $.fn.html;
$.fn.html = function(html,fn){
  fn = fn || function(){};
  var result =  this.oldHtml(html);
  fn();
  return result;
};
$('body').html(11,function(){alert("haha");});

Демо здесь.

Вы вносите изменения в какой-то элемент, а не элемент вынужден измениться чем-то, что вы должны уловить.


источник
Мне пришлось сегодня решить эту проблему. Я не мог редактировать код, который на самом деле вызывал html (), потому что он находится в сторонней библиотеке. Модифицированная версия этого идеально подошла мне. Я сделал так: $ .fn.oldHtml = $ .fn.html (); $ .fn.html = function (e) {var result = this.oldHtml (e); this.trigger ('afterHtmlChange', e);} Теперь я могу связать любые события, которые я хочу, с вновь созданным событием afterHtmlChange для любого элемента, которое будет срабатывать всякий раз, когда что-либо вызывает jQuery html () fn.
Дэниел Ховард
Упс, небольшая ошибка. Fn в моем комментарии выше должно быть: function (e) {var result = this.oldHtml (e); this.trigger ('afterHtmlChange', e); return result;}
Дэниел Ховард
0

Я написал фрагмент, который будет проверять изменение элемента в событии.

Итак, если вы используете сторонний код javascript или что-то в этом роде, и вам нужно знать, когда что-то появляется или изменяется при нажатии, тогда вы можете.

Допустим, что для приведенного ниже фрагмента вам нужно знать, когда содержимое таблицы изменяется после нажатия кнопки.

$('.button').live('click', function() {

            var tableHtml = $('#table > tbody').html();
            var timeout = window.setInterval(function(){

                if (tableHtml != $('#table > tbody').
                    console.log('no change');
                } else {
                    console.log('table changed!');
                    clearInterval(timeout);
                }

            }, 10);
        });

Псевдокод:

  • Как только вы нажмете кнопку
  • захватывается HTML-код элемента, который вы ожидаете изменить
  • затем мы постоянно проверяем html элемента
  • когда мы обнаруживаем, что html отличается, мы останавливаем проверку
Эндрю Аткинсон
источник
0

Мы можем добиться этого с помощью событий мутации . Согласно сайту www.w3.org, модуль событий мутации предназначен для уведомления о любых изменениях в структуре документа, включая изменения атрибутов и текста. Подробнее СОБЫТИЯ МУТАЦИИ

Например :

$("body").on('DOMSubtreeModified', "#content", function() {
    alert('Content Modified'); // do something
});
Санчит Гупта
источник
Это уже давно не рекомендуется. Следует использовать наблюдателей за
Карлес
-3

Невозможно, я считаю, что произошло событие, связанное с изменением содержимого, но это определенно не x-browser

Должен ли я сказать, что невозможно без каких-то неприятных интервалов в фоновом режиме!

Красный квадрат
источник
21
невозможность - ничто!
jrharshath 07