jQuery的某些类的div检测已添加到DOM


90

.on()用来绑定在页面加载后创建的div事件。它可以很好地用于单击,mouseenter ...,但是我需要知道何时添加了MyClass类的新div。我正在寻找这个:

$('#MyContainer').on({

  wascreated: function () { DoSomething($(this)); }

}, '.MyClass');

我该怎么做呢?我设法在没有插件的情况下编写了整个应用程序,我希望保持这种状态。

谢谢。


生成元素的是您自己的代码吗?如果是这样,您可以在创建它时进行检查并采取相应措施。
超现实主义梦想

是的,的确如此,但是使用.on(),我可以在document.ready上绑定事件,然后在生成HTML时不必担心绑定。我正在寻找与DoSomething相同的行为。
frenchie

您可以使用$(“ div / your-selector”)。hasClass(“ MyClass”); 检查div是否具有特定的类。我想您可以使用此api。
KBN 2012年

.on()仅用于事件。您可以设置一个自定义事件,但是在创建新元素时仍然必须触发该事件。
超现实主义梦想

Answers:


102

以前,人们可以使用jQuery的domManip方法来捕获所有jQuery dom操作,并查看插入了哪些元素等。但是jQuery团队在jQuery 3.0+中将其关闭,因为通常不是通过这种方式连接jQuery方法的好方法,因此,内部domManip方法不再在核心jQuery代码之外可用。

不推荐使用突变事件,因为以前人们可以做类似的事情

$(document).on('DOMNodeInserted', function(e) {
    if ( $(e.target).hasClass('MyClass') ) {
       //element with .MyClass was inserted.
    }
});

应该避免这种情况,今天应该改用突变观察者,这样可以工作

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        console.log(mutation)
        if (mutation.addedNodes && mutation.addedNodes.length > 0) {
            // element added to DOM
            var hasClass = [].some.call(mutation.addedNodes, function(el) {
                return el.classList.contains('MyClass')
            });
            if (hasClass) {
                // element has class `MyClass`
                console.log('element ".MyClass" added');
            }
        }
    });
});

var config = {
    attributes: true,
    childList: true,
    characterData: true
};

observer.observe(document.body, config);

Firefox和webkit几乎应该可以,但是在IE中对此的支持却很差。它应该在IE9中工作,但在IE8中可能没有那么大的作用。我知道我已经看到了解决方法,并且我还没有真正在IE中对此进行过测试,所以请先对其进行测试,如果它无法正常工作,请查看是否存在解决方法。有一个插件看起来像在这里添加了IE支持,但是还没有尝试过,只是在Google搜索中找到了它。
2012年

2
我最初使用的是您的答案,但事实证明它不能跨浏览器工作是一个问题。然后,我很快想出了一种解决方法,可以首先避免该问题。然后,几周前,在我的代码中再次出现了检测节点插入的问题。这次,我在答案中发布的代码完全可以正常工作,跨浏览器,没有错误。所以这就是为什么我的回答被接受的原因。这就是SO的工作方式,OP决定他接受哪个答案,然后人群对答案进行投票。随着时间的流逝,人们将投票决定最适合他们的答案。
frenchie

2
而且,我想说的是,您为我节省了很多时间,提供了高质量的答案,帮助了我多次。将接受的答案更改为我的答案完全是基于代码以及它如何适合我必须解决的问题。
frenchie

带有此代码“未捕获的TypeError:无法读取未定义的属性'包含'”
gordie

53

这是我的插件,确实可以做到这一点-jquery.initialize

用法与您使用.each函数的用法相同,但是.initialize在元素上使用函数时,不同之处.each在于它还会初始化以后添加的元素,而无需任何其他代码-无论您是使用AJAX还是其他方式添加它。

初始化具有与.each函数完全相同的语法

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

但是现在,如果新元素匹配.some-element选择器出现在页面上,它将被立即初始化。添加新项目的方式并不重要,您无需关心任何回调等。

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

插件基于 MutationObserver


非常感谢。
布兰登·哈里斯

如何停止初始化?添加想要的内容后,我想停止观看...
Evgeny Vostok

$(“。some-element”)。initialize [..]已过时。使用$ .initialize(“。addDialog”,function(){$('。noData')。hide();}); 代替。
Heimi

是否可以仅对动态添加的元素(例如,通过Ajax)执行该.initialize函数,而跳过页面初始加载时已经存在的元素的回调?我正在尝试向其中添加一个参数以完成此操作,但到目前为止,我还没有使它起作用。callback options
Nevermore '18

您可以在github上添加有关此内容的问题。从技术上来说,现在您可以做到$('.myClass').addClass('ignore-initialize'); $.initialize('.myClass:not(.ignore-initialize)', callback);
pie6k '18

18

在审阅了这篇文章和其他几篇文章之后,我尝试将我认为最好的内容简化为一些简单的内容,使我能够检测何时插入一类元素,然后对这些元素进行操作

function onElementInserted(containerSelector, elementSelector, callback) {

    var onMutationsObserved = function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.addedNodes.length) {
                var elements = $(mutation.addedNodes).find(elementSelector);
                for (var i = 0, len = elements.length; i < len; i++) {
                    callback(elements[i]);
                }
            }
        });
    };

    var target = $(containerSelector)[0];
    var config = { childList: true, subtree: true };
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    var observer = new MutationObserver(onMutationsObserved);    
    observer.observe(target, config);

}

onElementInserted('body', '.myTargetElement', function(element) {
    console.log(element);
});

对我而言,重要的是,这允许a)目标元素存在于“ addedNodes”内的任何深度,并且b)仅在最初插入时才有能力处理该元素(无需搜索整个文档设置或忽略“已处理”)标志)。


1
您的情况应该是if(mutation.addedNodes.length)因为addedNodesremovedNodes数组总是存在于mutation其中childList(在IE11,Chrome53,FF49中已检查)。仍然为+1,因为您的答案是唯一addedNodes被考虑的答案(callback仅在添加节点时才调用);不仅在此线程上,而且在许多其他线程上。callback即使其他节点被删除,其他所有人也都在调用所有突变。
Vivek Athalye

17

3年的经验之后,这就是我如何收听“将某个类的元素添加到DOM中”的方法:您只需在jQueryhtml()函数中添加一个钩子,就像这样:

function Start() {

   var OldHtml = window.jQuery.fn.html;

   window.jQuery.fn.html = function () {

     var EnhancedHtml = OldHtml.apply(this, arguments);

     if (arguments.length && EnhancedHtml.find('.MyClass').length) {

         var TheElementAdded = EnhancedHtml.find('.MyClass'); //there it is
     }

     return EnhancedHtml;
   }
}

$(Start);

如果您使用的是jQuery,则此方法有效。而且它不依赖于浏览器特定的事件DOMNodeInserted,该事件与跨浏览器不兼容。我还添加了相同的实现.prepend()

总的来说,这对我来说是一种魅力,希望对你也一样。


6
嗯,如果您仅使用jQuery的html助手来修改DOM,而不仅仅是“使用jQuery”,那么我想澄清一下。例如,使用添加的元素jQuery.append不会触发此事件。
iameli

1
是的,这就是为什么我澄清说我使用.preprend()添加了相同的实现,并且如果您使用.append()然后使用.append()做相同的事情
frenchie 2015年

使用CSS3动画有一种更快的方法。开源库还提供了更简单的代码:insertionQ('#intercom-container').every(function(/element){ element.style.display = 'none'; });
Dan Dascalescu 2015年

3
为什么要下票?这实际上有效:没有插件,没有hacky setTimeout函数。
frenchie

2
赞成-这是一个有效的选项-为什么在全世界(!!!)都赞成这种看法????Dan,CSS3动画不是XBC:caniuse.com/#search=keyframes ; davidwalsh.name/detect-node-insertion
科迪

6

你可以使用突变事件

http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-mutationevents

编辑

来自MDN:https//developer.mozilla.org/zh-CN/docs/Web/Guide/Events/Mutation_events

不推荐使用此功能已从Web上删除。尽管某些浏览器可能仍支持它,但是它正在被删除。不要在新旧项目中使用它。使用它的页面或Web应用程序可能随时中断。

突变观察者是DOM4中突变事件的提议替代者。它们将包含在Firefox 14和Chrome 18中。

https://developer.mozilla.org/en/docs/Web/API/MutationObserver

MutationObserver为开发人员提供了一种对DOM中的更改做出反应的方法。它旨在替代DOM3事件规范中定义的突变事件。

用法示例

以下示例来自http://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/

// select the target node
var target = document.querySelector('#some-id');

// create an observer instance
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type);
  });    
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();

2
mdn称,不赞成使用突变事件,而赞成使用MutationObservers
Olga

既然IE10已经停产,可以肯定地说MutationObserver得到了广泛支持。
rymo '16

0

adeneo的答案有两个补充:

(1)我们可以换线

return el.classList.contains('MyClass');

if( el.classList ) {
    return el.classList.contains('MyClass');
} else {
    return false;
}

因此,我们不会看到该"Uncaught TypeError: Cannot read property 'contains' of undefined"错误。

(2)附加subtree: trueconfig找到添加的节点递归地在所有添加元素。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.