JQuery 或 vanilla Javascript 中的 DOM Mutation 事件 [英] DOM Mutation event in JQuery or vanilla Javascript

查看:17
本文介绍了JQuery 或 vanilla Javascript 中的 DOM Mutation 事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 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);}

A

的小提琴演示

B.你知道什么类型的元素将被附加到:

HTMLDivElement.prototype.__appendChild = HTMLDivElement.prototype.appendChild;HTMLDivElement.prototype.appendChild = function(){alert('添加了新项目');HTMLDivElement.prototype.__appendChild(this,arguments);}

B

的小提琴演示

(请注意,IE <8 或任何其他不支持 DOM 原型的浏览器不支持解决方案 B.)

同样的技术可以很容易地用于所有底层 DOM 突变函数,例如 insertBeforereplaceChildremoveChild.>

这是总体思路,这些演示几乎可以适用于任何其他用例——假设您想撒网并捕获所有添加的内容,而不管类型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>');

C

的小提琴演示

更新 2

正如 Tim Down 评论的那样,上述解决方案也不适用于 IE <8 因为appendChild 不是Function 并且不支持callapply.我想如果 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); 
}

fiddle demo for A

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); 
}

fiddle demo for B

(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>');

fiddle demo for C

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆