Событие DOM Mutation в JQuery или ванильном Javascript

Есть ли какие-либо события мутации DOM в JQuery или в ванильном Javascript, которые запускают кросс-браузер?

Чтобы уточнить, скажем, у меня на странице есть скрипт, который вставляет div в тело. У меня нет доступа к сценарию, и я не знаю, когда div был вставлен. Мне было интересно, есть ли событие мутации DOM, для которого я могу добавить слушателя, чтобы знать, когда элемент был вставлен. Я знаю, что могу использовать таймер для периодической проверки вставки, но мне не очень нравятся накладные расходы, которые это может наложить.

6 ответов

Это, конечно, хак, но почему бы не исправить патчи базовых методов DOM, используемых для вставки узлов? Есть несколько способов сделать это:

А. Вы знаете, к какому конкретному элементу будет добавлен:

var c = document.getElementById('#container');
c.__appendChild = c.appendChild;
c.appendChild = function(){
     alert('new item added');
     c.__appendChild.apply(c, arguments); 
}

Скрипка демо для А

Б. Вы знаете, какой тип элемента будет добавлен:

HTMLDivElement.prototype.__appendChild = HTMLDivElement.prototype.appendChild;
HTMLDivElement.prototype.appendChild = function(){
    alert('new item added');
    HTMLDivElement.prototype.__appendChild(this,arguments); 
}

Скрипка демо для B

(Обратите внимание, что решение B не поддерживается IE < 8 или любой другой браузер, который не поддерживает прототипы DOM.)

Эту же технику можно так же легко использовать для всех основных функций мутации DOM, таких как insertBefore, replaceChild или же removeChild,

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


ОБНОВИТЬ

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

var DOMwatcher = function(root, callback){
  var __appendChild = document.body.appendChild;

  var patch = function(node){
    if(typeof node.appendChild !== 'undefined' && node.nodeName !== '#text'){
      node.appendChild = function(incomingNode){
        callback(node, incomingNode);
        patch(incomingNode);
        walk(incomingNode);
        __appendChild.call(node, incomingNode);
      };
    }
    walk(node);  
  };

  var walk = function(node){
    var i = node.childNodes.length;
    while(i--){
      patch(node.childNodes[i]);
    }
  };

  patch(root);

};

DOMwatcher(document.body, function(targetElement, newElement){ 
   alert('append detected');    
});

$('#container ul li').first().append('<div><p>hi</p></div>');
$('#container ul li div p').append('<a href="#foo">bar</a>');

Скрипка демо для C

ОБНОВЛЕНИЕ 2

Как прокомментировал Tim Down, вышеуказанное решение также не будет работать в IE < 8 так как appendChild это не Function и не поддерживает call или же apply, Я полагаю, вы всегда можете вернуться к неуклюжим, но верным setInterval метод, если typeof document.body.appendChild !== 'function',

Есть некоторые устаревшие события мутации DOM, такие как DOMNodeInserted а также DOMNodeInsertedIntoDocument это все еще работает для меня в Chrome 14 и IE9.

Смотрите пример на http://jsfiddle.net/Kai/WTJq6/

См. Их всех в проекте W3C на http://www.w3.org/TR/DOM-Level-3-Events/

JCADE (JQuery Create и Destroy Events) сделает это. Он использует поведения для событий мутации IE и DOM для других браузеров. Он не использует события синхронизации и не переносит методы JQuery, такие как livequery.

https://github.com/snesin/jcade

    $ (document).create ("a", function (event) {
      оповещение ( event.target);
    });

Думаю, не без плагина, но я не удивлюсь, если я ошибаюсь.

Мое исследование нашло несколько на выбор.

Вот один из них: http://plugins.jquery.com/project/mutation-events

Вот еще один: https://www.adaptavist.com/display/jQuery/Mutation+Events

Для этого можно использовать плагин livequery. В версии 1.x a таймер использовался для периодической проверки любых изменений. Однако более новая ветка версии 2.x, кажется, работает без периодического таймаута (не проверено).

Если вы ищете альтернативу этому методу, вот http://www.jqui.net/jquery-projects/jquery-mutate-official/ который также позволяет вам добавлять события самостоятельно и следить за практически любыми изменениями., изменение имени класса, изменение высоты, изменение ширины.

Другие вопросы по тегам