JQuery 或 vanilla Javascript 中的 DOM Mutation 事件 [英] DOM Mutation event in JQuery or vanilla Javascript
问题描述
在 JQuery 或 vanilla Javascript 中是否有任何 DOM 突变事件会触发跨浏览器?
澄清一下,假设我的页面上有一个脚本,它在正文中插入了一个 div.我无权访问脚本,也不知道 div 何时插入.我想知道是否有我可以添加侦听器的 DOM 突变事件,以了解何时插入元素.我知道我可以使用计时器来定期检查插入,但是,我真的不喜欢这会带来的开销.
这当然是一个 hack,但为什么不修补用于插入节点的底层 DOM 方法呢?有几种方法可以做到这一点:
A.您知道什么特定元素将被附加到:
var c = document.getElementById('#container');c.__appendChild = c.appendChild;c.appendChild = function(){alert('添加了新项目');c.__appendChild.apply(c, arguments);}
的小提琴演示B.你知道什么类型的元素将被附加到:
HTMLDivElement.prototype.__appendChild = HTMLDivElement.prototype.appendChild;HTMLDivElement.prototype.appendChild = function(){alert('添加了新项目');HTMLDivElement.prototype.__appendChild(this,arguments);}
的小提琴演示(请注意,IE <8
或任何其他不支持 DOM 原型的浏览器不支持解决方案 B.)
同样的技术可以很容易地用于所有底层 DOM 突变函数,例如 insertBefore
、replaceChild
或 removeChild
.>
这是总体思路,这些演示几乎可以适用于任何其他用例——假设您想撒网并捕获所有添加的内容,而不管类型AND 确保它适用于 所有浏览器 除了 IE <8
?(参见下面的示例 C)
更新
C. 递归遍历 DOM,交换每个元素上的函数以触发回调,然后将相同的补丁应用于任何被附加的子元素.
var DOMwatcher = function(root, callback){var __appendChild = document.body.appendChild;var 补丁 = 函数(节点){if(typeof node.appendChild !== 'undefined' && node.nodeName !== '#text'){node.appendChild = 函数(incomingNode){回调(节点,incomingNode);补丁(传入节点);步行(传入节点);__appendChild.call(节点,incomingNode);};}步行(节点);};var walk = 函数(节点){var i = node.childNodes.length;当我 - ){补丁(节点.childNodes[i]);}};补丁(根);};DOMwatcher(document.body, function(targetElement, newElement){alert('检测到追加');});$('#container ul li').first().append('<div><p>hi</p></div>');$('#container ul li div p').append('<a href="#foo">bar</a>');
的小提琴演示更新 2
正如 Tim Down 评论的那样,上述解决方案也不适用于 IE <8
因为appendChild
不是Function
并且不支持call
或apply
.我想如果 typeof document.body.appendChild !== 'function'
.
Are there any DOM mutation events in JQuery or in vanilla Javascript that fire cross browser?
To clarify, say I have a script on my page which inserts a div into the body. I don't have access to the script and I don't know when the div has been inserted. I was wondering if there's a DOM mutation event that I can add a listener for, to know when an element has been inserted. I know I can use a timer to periodically check for the insertion but, I don't really like the overhead that this would impose.
This is certainly a hack, but why not patch the underlying DOM methods used to insert the nodes? There are a couple ways to do this:
A. You know what specific element will be appended to:
var c = document.getElementById('#container');
c.__appendChild = c.appendChild;
c.appendChild = function(){
alert('new item added');
c.__appendChild.apply(c, arguments);
}
B. You know what type of element will be appended to:
HTMLDivElement.prototype.__appendChild = HTMLDivElement.prototype.appendChild;
HTMLDivElement.prototype.appendChild = function(){
alert('new item added');
HTMLDivElement.prototype.__appendChild(this,arguments);
}
(Note that solution B is not supported by IE < 8
or any other browser which does not support DOM prototypes.)
This same technique could just as easily be used on all the underlying DOM mutation functions such as insertBefore
, replaceChild
or removeChild
.
That's the general idea, these demos could be adapted for pretty much any other use case -- say you want to cast a wide net and catch all additions regardless of type AND make sure it works across all browsers everything but IE < 8
? (see example C below)
UPDATE
C. Recursively walk the DOM, swap out the function on every element to trigger a callback, and then apply the same patch to any children being appended.
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>');
UPDATE 2
As Tim Down commented, the above solution also won't work in IE < 8
because appendChild
is not a Function
and does not support call
or apply
. I suppose you could always fall back to the clunky but trusty setInterval
method if typeof document.body.appendChild !== 'function'
.
这篇关于JQuery 或 vanilla Javascript 中的 DOM Mutation 事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!