是否存在 JQuery 或原生 JavaScript 中可跨浏览器触发的 DOM 变化事件?
为了澄清,假设我在页面上有一个脚本,它将一个 div 插入到 body 中。我无法访问该脚本,也不知道何时插入了该 div。我想知道是否有 DOM 变化事件可以添加监听器来知道何时插入了元素。我知道我可以使用定时器周期性地检查插入情况,但我不喜欢这样做会带来的开销。
是否存在 JQuery 或原生 JavaScript 中可跨浏览器触发的 DOM 变化事件?
为了澄清,假设我在页面上有一个脚本,它将一个 div 插入到 body 中。我无法访问该脚本,也不知道何时插入了该 div。我想知道是否有 DOM 变化事件可以添加监听器来知道何时插入了元素。我知道我可以使用定时器周期性地检查插入情况,但我不喜欢这样做会带来的开销。
这确实是一种hack方法,但为什么不修补用于插入节点的底层DOM方法呢?有几种方法可以实现:
A. 如果您知道将要附加到哪个具体元素:
var c = document.getElementById('#container');
c.__appendChild = c.appendChild;
c.appendChild = function(){
alert('new item added');
c.__appendChild.apply(c, arguments);
}
这里有一个演示A的JSFiddle。
B。你知道将要添加到哪种类型的元素中:
HTMLDivElement.prototype.__appendChild = HTMLDivElement.prototype.appendChild;
HTMLDivElement.prototype.appendChild = function(){
alert('new item added');
HTMLDivElement.prototype.__appendChild(this,arguments);
}
(请注意,解决方案B不支持IE < 8
或任何不支持DOM原型的其他浏览器。)
同样的技术也可以很容易地用于所有基础的DOM变异函数,如insertBefore
、replaceChild
或removeChild
。
这是一个通用的思路,这些演示可以适应几乎任何其他用例——比如说您想铺设广泛的网并捕获所有添加,而不管类型并且确保它在IE < 8
以外的其他浏览器上工作吗?(请参见下面的C示例)
更新
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评论所说,由于appendChild
不是一个函数且不支持call
或apply
,上面提到的解决方案在IE < 8中也无法工作。如果typeof document.body.appendChild !== 'function'
,您可以始终退回到笨重但可靠的setInterval
方法。
appendChild()
)不需要是“Function”对象(在IE < 9中确实不是)。 - Tim DownappendChild
不是一个Function
的浏览器中,这个解决方案将会失败,因为它不响应call
或apply
。很好地发现了这一点,我已经更新了答案以反映这一点。然而,你会发现上面的代码在IE 8中确实可以工作。 - Daniel Mendel有一些被弃用的DOM变异事件,比如DOMNodeInserted
和DOMNodeInsertedIntoDocument
在Chrome14和IE9中仍然可用。
$( document ).create( "a", function( event ) { alert( event.target ); });
可以使用livequery插件来实现此功能。在1.x版本中,定时器被用于定期检查任何更改。然而,更新的2.x分支似乎可以在没有定期超时的情况下工作(未经测试)。
如果您正在寻找这种方法的替代方案,这里有一个http://www.jqui.net/jquery-projects/jquery-mutate-official/,它也可以让您自己添加事件并监视几乎任何更改、类名更改、高度更改、宽度更改。