【问题标题】:jquery detecting div of certain class has been added to DOMjquery检测某些类的div已添加到DOM
【发布时间】:2012-05-02 14:05:15
【问题描述】:

我正在使用.on() 绑定页面加载后创建的 div 事件。它适用于单击,鼠标输入......但我需要知道何时添加了 MyClass 类的新 div。我正在寻找这个:

$('#MyContainer').on({

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

}, '.MyClass');

我该怎么做?我已经设法在没有插件的情况下编写了整个应用程序,并且我希望保持这种方式。

谢谢。

【问题讨论】:

  • 是您自己的代码在生成元素吗?如果是这样,您可以在创建时检查并采取相应措施。
  • 是的,确实如此,但是使用 .on(),我可以在 document.ready 处绑定事件,然后在生成 HTML 时不必担心绑定。我正在寻找与 DoSomething 相同的行为。
  • 你可以使用 $("div/your-selector").hasClass("MyClass");检查 div 是否具有特定的类。我想你可以把这个 api 用于你的使用。
  • .on() 仅用于事件。您可以设置自定义事件,但您仍然必须在创​​建新元素时触发该事件。

标签: jquery


【解决方案1】:

以前可以挂钩到 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.
    }
});

应该避免这种情况,今天应该使用 Mutation Observers 代替,它的工作原理是这样的

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支持here,但没试过,谷歌搜了一下。
  • 我最初使用了您的答案,但它不能跨浏览器工作的事实是一个问题。然后,我很快想出了一个解决方法来避免这个问题。然后,几周前,检测节点插入的问题再次出现在我的代码中。这一次,我在我的答案中发布的代码完全像它应该的那样工作,跨浏览器并且没有任何错误。所以这就是为什么我将我的答案改为接受的原因;这就是 SO 的工作方式,OP 决定他接受哪个答案,然后人群对答案进行投票。随着时间的推移,人们会投票决定哪个答案最适合他们。
  • 另外,我想说的是,您多次帮助我提供高质量的答案,挽救了我的一天。将接受的答案更改为我的完全基于代码以及它如何适合我必须解决的问题。
  • 使用此代码得到“未捕获的类型错误:无法读取未定义的属性‘包含’”
  • 在上面寻找 agrul 的答案来修复 Uncaught TypeError,另外还响应子树元素,如果你需要这个,就像我做的那样。
【解决方案2】:

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

用法与您使用.each 函数相同,但在元素上使用.initialize 函数,与.each 的区别在于它还将初始化将来添加的元素而无需任何额外代码 - 无论您是否添加它与 AJAX 或其他任何东西。

Initialize 的语法与 .each 函数完全相同

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

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

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

插件基于MutationObserver

【讨论】:

  • 非常感谢。
  • 如何停止初始化?一旦添加了我要查找的内容,我就想停止观看...
  • $(".some-element").initialize[..] 已弃用。使用 $.initialize(".addDialog", function () { $('.noData').hide(); });而是。
  • 是否可以对动态添加的元素(例如通过 Ajax)执行 .initialize 函数的 callback only,并跳过已经存在的元素的回调页面最初加载?我正在尝试向options 添加一个参数以完成此操作,但到目前为止我还没有完成此操作。
  • 您可以在 github 上添加关于此的问题。现在,从技术上讲,你可以这样做 $('.myClass').addClass('ignore-initialize'); $.initialize('.myClass:not(.ignore-initialize)', callback);
【解决方案3】:

在查看了这篇文章和其他几篇文章后,我尝试将我认为最好的部分提炼成简单的东西,让我能够检测何时插入了一类元素,然后对这些元素采取行动 .

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)目标元素存在于“addNodes”中的任何深度,b)仅在最初插入时处理元素的能力(无需搜索整个文档设置或忽略“已经-processed”标志)。

【讨论】:

  • 您的条件应该是if(mutation.addedNodes.length),因为addedNodesremovedNodes 数组始终存在于childList 类型的mutation 中(在IE11、Chrome53、FF49 中检查)。仍然+1,因为您的答案是考虑addedNodes 的唯一答案(仅在添加节点时才调用callback);不仅在这个线程上,而且在许多其他线程上。其他人只是为所有突变调用callback,即使节点正在被删除。
  • 很好 - 效果很好。谢谢。
【解决方案4】:

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()添加了相同的实现

总的来说,这对我来说就像一个魅力,希望对你也一样。

【讨论】:

  • 嗯——我想澄清一下,如果您专门使用 jQuery 的 html 帮助器来修改 DOM,而不仅仅是“使用 jQuery”,那么这很有效。使用 jQuery.append 添加的元素不会触发此事件。
  • 是的,这就是为什么我澄清说我用 .preprend() 添加了相同的实现,如果你使用 .append() 然后用 .append() 做同样的事情
  • 有一个更快的方法,使用CSS3 animations。开源库还提供了更简单的代码:insertionQ('#intercom-container').every(function(/element){ element.style.display = 'none'; });
  • 为什么投反对票?这实际上有效:没有插件,也没有 hacky setTimeout 函数。
  • 赞成——这是一个有效的选择——为什么世界上(!!!)这被反对了?????? Dan,CSS3 动画不是 XBC:caniuse.com/#search=keyframesdavidwalsh.name/detect-node-insertion.
【解决方案5】:

你可以使用突变事件

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

编辑

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

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

Mutation Observers 是 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();

【讨论】:

  • 根据mdn,Mutation 事件几乎已被弃用,转而支持 MutationObservers
  • 现在 IE10 已停产,可以说MutationObserver 得到广泛支持。
【解决方案6】:

对 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) 在config 中添加subtree: true 以在所有添加的元素中递归查找添加的节点。

【讨论】:

  • 感谢 subtree:true 并修复错误
猜你喜欢
  • 2015-04-24
  • 2011-01-01
  • 2013-11-12
  • 2023-03-26
  • 2011-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-31
相关资源
最近更新 更多