检测DOM中的更改

当一些div或input被添加到html时,我想执行一个函数。 这可能吗?

例如,添加一个文本input,然后调用该函数。

2015更新,现代浏览器支持新的MutationObserver

Chrome 18+,Firefox 14+,IE 11+,Safari 6+

如果您需要支持较老的答案,您可以尝试回到下面这个5 (!)年答案中提到的方法。 有龙。 请享用 :)


别人正在改变文件? 因为如果您完全控制了更改,您只需创build自己的domChanged API(包含函数或自定义事件),并在修改内容的任何地方触发/调用它。

DOM级别2具有突变事件types ,但IE的旧版本不支持。 请注意,突变事件在DOM3 Events规范中已被弃用,并且会有性能损失 。

您可以尝试在IE中使用onpropertychange来模拟突变事件(如果没有可用的方法,则回退到暴力破解方法)。

对于一个完整的 domChange,间隔可能是一个过度杀手。 想象一下,你需要存储整个文档的当前状态,并检查每个元素的每个属性是否相同。

也许如果你只对元素和顺序感兴趣(就像你在你的问题中提到的那样), getElementsByTagName("*")就可以工作。 如果添加元素,删除元素,replace元素或更改文档的结构,将自动触发。

我写了一个概念certificate:

 (function (window) { var last = +new Date(); var delay = 100; // default delay // Manage event queue var stack = []; function callback() { var now = +new Date(); if (now - last > delay) { for (var i = 0; i < stack.length; i++) { stack[i](); } last = now; } } // Public interface var onDomChange = function (fn, newdelay) { if (newdelay) delay = newdelay; stack.push(fn); }; // Naive approach for compatibility function naive() { var last = document.getElementsByTagName('*'); var lastlen = last.length; var timer = setTimeout(function check() { // get current state of the document var current = document.getElementsByTagName('*'); var len = current.length; // if the length is different // it's fairly obvious if (len != lastlen) { // just make sure the loop finishes early last = []; } // go check every element in order for (var i = 0; i < len; i++) { if (current[i] !== last[i]) { callback(); last = current; lastlen = len; break; } } // over, and over, and over again setTimeout(check, delay); }, delay); } // // Check for mutation events support // var support = {}; var el = document.documentElement; var remain = 3; // callback for the tests function decide() { if (support.DOMNodeInserted) { window.addEventListener("DOMContentLoaded", function () { if (support.DOMSubtreeModified) { // for FF 3+, Chrome el.addEventListener('DOMSubtreeModified', callback, false); } else { // for FF 2, Safari, Opera 9.6+ el.addEventListener('DOMNodeInserted', callback, false); el.addEventListener('DOMNodeRemoved', callback, false); } }, false); } else if (document.onpropertychange) { // for IE 5.5+ document.onpropertychange = callback; } else { // fallback naive(); } } // checks a particular event function test(event) { el.addEventListener(event, function fn() { support[event] = true; el.removeEventListener(event, fn, false); if (--remain === 0) decide(); }, false); } // attach test events if (window.addEventListener) { test('DOMSubtreeModified'); test('DOMNodeInserted'); test('DOMNodeRemoved'); } else { decide(); } // do the dummy test var dummy = document.createElement("div"); el.appendChild(dummy); el.removeChild(dummy); // expose window.onDomChange = onDomChange; })(window); 

用法:

 onDomChange(function(){ alert("The Times They Are a-Changin'"); }); 

这适用于IE 5.5+,FF 2+,Chrome,Safari 3+和Opera 9.6+

到目前为止,这是最小的代码:

IE9 +,FF,Webkit:

如果需要,使用MutationObserver并回退到弃用的突变事件 :
(以下示例仅适用于附加或移除节点的DOM更改)

 var observeDOM = (function(){ var MutationObserver = window.MutationObserver || window.WebKitMutationObserver, eventListenerSupported = window.addEventListener; return function(obj, callback){ if( MutationObserver ){ // define a new observer var obs = new MutationObserver(function(mutations, observer){ if( mutations[0].addedNodes.length || mutations[0].removedNodes.length ) callback(); }); // have the observer observe foo for changes in children obs.observe( obj, { childList:true, subtree:true }); } else if( eventListenerSupported ){ obj.addEventListener('DOMNodeInserted', callback, false); obj.addEventListener('DOMNodeRemoved', callback, false); } }; })(); // Observe a specific DOM element: observeDOM( document.getElementById('dom_element') ,function(){ console.log('dom changed'); }); 

我最近写了一个插件,完全是 – jquery.initialize

您可以像使用.each函数一样使用它

 $(".some-element").initialize( function(){ $(this).css("color", "blue"); }); 

.each的不同之处在于 – 它需要你的select器,在这种情况下.some-element并在将来等待这个select器的新元素,如果这个元素将被添加,它也将被初始化。

在我们的例子中,初始化函数只是将元素的颜色改为蓝色。 所以如果我们要添加新的元素(不pipe是用ajax还是F12检查器或者其他的东西),比如:

 $("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color! 

插件将立即启动它。 插件也确保一个元素只被初始化一次。 所以,如果你添加元素,然后从身体.deatch() ,然后再添加它,它不会被再次初始化。

 $("<div/>").addClass('some-element').appendTo("body").detach() .appendTo(".some-container"); //initialized only once 

插件是基于MutationObserver – 它可以在IE9和10上工作,具有依赖性,详见自述文件页面 。

或者你可以简单地创build自己的事件 ,到处运行

  $("body").on("domChanged", function () { //dom is changed }); $(".button").click(function () { //do some change $("button").append("<span>i am the new change</span>"); //fire event $("body").trigger("domChanged"); }); 

完整的示例http://jsfiddle.net/hbmaam/Mq7NX/

如何扩展一个jQuery的呢?

  (function () { var ev = new $.Event('remove'), orig = $.fn.remove; var evap = new $.Event('append'), origap = $.fn.append; $.fn.remove = function () { $(this).trigger(ev); return orig.apply(this, arguments); } $.fn.append = function () { $(this).trigger(evap); return origap.apply(this, arguments); } })(); $(document).on('append', function (e) { /*write your logic here*/ }); $(document).on('remove', function (e) { /*write your logic here*/ ) }); 

Jquery 1.9+已经build立了对此的支持(我听说没有testing过)。