jQuery 选择器可以与 DOM 变异观察者一起使用吗?

Posted

技术标签:

【中文标题】jQuery 选择器可以与 DOM 变异观察者一起使用吗?【英文标题】:Can jQuery selectors be used with DOM mutation observers? 【发布时间】:2012-09-17 18:06:26 【问题描述】:

html5 包含"mutation observers" 的概念,用于监控浏览器 DOM 的变化。

您的观察者回调将传递看起来很像 DOM 树 sn-ps 的数据。我不知道它们到底是不是这样,或者它们是如何工作的。

但是,当您编写代码以与您无法控制的第 3 方网站交互时,例如使用 Greasemonkey 脚本或 Google Chrome 用户脚本,您必须检查传入的元素树以查找哪些信息是相关的给你。

使用选择器比手动遍历树要简单得多,就像使用任何 DOM 一样,尤其是对于跨浏览器代码。

有没有办法将 jQuery 选择器与传递给 HTML5 突变观察者回调的数据一起使用?

【问题讨论】:

相关问题:Is there a jQuery DOM change listener?, DOM Mutation event in JQuery or vanilla javascript 参见:Can I use Jquery selectors on an HTML string that is not attached to the DOM? 有一个 插件:github.com/kapetan/jquery-observe 【参考方案1】:

我知道这是一个老问题,但也许这可以帮助其他人寻找替代解决方案。我最近了解了 Mutation Observers 并想尝试将它们与 jQuery 一起使用。我想出了两种可能的方法并将它们变成插件。代码可用here。

第一种方法 (jquery.observeWithEvents.js) 使用 jQuery 的 trigger() 函数来触发 insertNoderemoveNode 事件,该事件可以通过 jQuery 的 on() 函数绑定到。第二种方法 (jquery.observeWithCallbacks.js) 使用传统的回调参数。请查看自述文件以获取示例和用法。

【讨论】:

【参考方案2】:

是的,您可以对返回到突变观察者回调的数据使用 jQuery 选择器。

See this jsFiddle.

假设你有这样的 HTML:

<span class="myclass">
    <span class="myclass2">My <span class="boldly">vastly</span> improved</span>
    text.
</span>

然后你设置一个观察者,像这样:

var targetNodes         = $(".myclass");
var MutationObserver    = window.MutationObserver || window.WebKitMutationObserver;
var myObserver          = new MutationObserver (mutationHandler);
var obsConfig           =  childList: true, characterData: true, attributes: true, subtree: true ;

//--- Add a target node to the observer. Can only add one node at a time.
targetNodes.each ( function () 
    myObserver.observe (this, obsConfig);
 );

function mutationHandler (mutationRecords) 
    console.info ("mutationHandler:");

    mutationRecords.forEach ( function (mutation) 
        console.log (mutation.type);

        if (typeof mutation.removedNodes == "object") 
            var jq = $(mutation.removedNodes);
            console.log (jq);
            console.log (jq.is("span.myclass2"));
            console.log (jq.find("span") );
        
     );

你会注意到我们可以在mutation.removedNodes上使用jQuery。


如果您随后从控制台运行 $(".myclass").html ("[censored!]");,您将从 Chrome 和 Firefox 获得此信息:

mutationHandler:
childList
jQuery(<TextNode textContent="\n ">, span.myclass2, <TextNode textContent="\n text.\n ">)
true
jQuery(span.boldly)

这表明您可以在返回的节点集上使用普通的 jQuery 选择方法。

【讨论】:

你知道它是否被 jQuery 官方支持,它是否适用于 jQuery 支持的所有浏览器以及哪些支持突变观察者?难道它只是碰巧在这些浏览器中工作?看起来可能是这种情况,因为行为似乎有所不同......无论如何我现在肯定会玩它! (-: 我认为这不是“官方”支持的问题。 removedNodesaddedNodes return lists of nodes 之类的东西。 jQuery 整天都在这样的列表上工作,一直如此。 ...该代码适用于 Firefox 和 Chrome,并且符合 W3C 规范。它应该适用于任何支持此类事件的浏览器。 当我问这个问题的时候,我的脑海里有一些模糊的回忆,关于“sn-ps”在过去没有附加到文档 DOM 时会有所不同,并且不确定在 jQuery 下是否仍然存在任何此类差异。 不幸的是,jsFiddle 不再工作了,至少在 FF 24.0 中。它会在控制台中发出一些警告并死掉。如果您无法复制问题,我可以列出错误。不过,它确实可以在 Chrome 30.0.something 中使用。 @Gutza,我刚刚在 FF 24 和 Chrome 最新版本中对其进行了测试。它仍然有效,我没有看到任何错误。从干净的 FF 配置文件或其他机器重试。【参考方案3】:

我没有任何个人代码 sn-ps,但我有三个资源可能会有所帮助:

Mutabor Github Repository Article + JQuery Utility for Mutators "jquery-mutation-summary" - extension of mutation-summary(可能是这三个中最好的)

来自链接 #3 'jquery-mutation-summary' 库的示例:

// Use document to listen to all events on the page (you might want to be more specific)
var $observerSummaryRoot = $(document);

// Simplest callback, just logging to the console
function callback(summaries)
    console.log(summaries);


// Connect mutation-summary
$observerSummaryRoot.mutationSummary("connect", callback, [ all: true ]);

// Do something to trigger mutationSummary
$("<a />",  href: "http://joelpurra.github.com/jquery-mutation-summary").text("Go to the jquery-mutation-summary website").appendTo("body");

// Disconnect when done listening
$observerSummaryRoot.mutationSummary("disconnect");

【讨论】:

嗯,我只是尝试使用Mutation Summary 的非 jQuery 原始版本,但发现它不适用于没有考虑用户脚本设计的页面。它擅长观察 idclass 引用的元素的更改,但当您关心的所有更改都是几个元素深度或生成的 ids 和 classNames 时,它就不那么好了。 在我看来,jQuery 在这种情况下只是装点门面。我错过了什么吗?【参考方案4】:

我正在处理我正在处理的 Stack Exchange 脚本的一个非常相似的问题,我需要能够监视 DOM 的更改。 jQuery 文档没有任何帮助,但我确实发现 DOMNodeInserted 事件在 Chrome 中有效:

document.addEventListener("DOMNodeInserted", function(event)
    var element = event.target;

    if (element.tagName == 'DIV') 
        if (element.id == 'seContainerInbox') 
            //alert($('#seContainerInbox').parent().get(0).tagName);
            trimStoredItems();
            $('#seTabInbox').click();
            //   var newCount = getNewCount();
            // if there are new inbox items, store them for later
            storeNewInboxItems();
            applyNewStyleToItems();
        
    
);

我不能 100% 确定这是否适用于 Firefox,因为我在开发过程中还没有走那么远。希望这会有所帮助!

【讨论】:

我正在使用WebKitMutationObserver(),我认为它是新的并受支持,旧的东西已被弃用。我不确定DOMNodeInserted 是否属于“旧东西”。 WebKitMutationObserver 传递给你一个突变对象,虽然我猜它本身不是 DOM 基本上是一个 DOM 引用包。我想知道我是否可以用 jQuery 包装它或其中的一些引用... 我自己没有使用过这个,但从你描述它的方式来看,我怀疑你可能不得不自己访问 RAW DOM 元素,这样你就可以将它们传递给一个 jQuery 对象,就像从两个谜题。我想这真的取决于实际的数据类型。也许看看“typeof”给你什么,看看它是否可以轻松包装。希望这会有所帮助! DOMNodeInserted 不是突变观察者的一部分。它是突变观察者取代的旧的、有缺陷的、已弃用的突变事件系统! @BrockAdams - 如果你有答案,你应该发布一个答案。实际上,一旦遇到它,我就打算用我自己的代码中更好的东西来替换它。

以上是关于jQuery 选择器可以与 DOM 变异观察者一起使用吗?的主要内容,如果未能解决你的问题,请参考以下文章

jQuery学习笔记:this相关问题及选择器

为啥 jQuery UI 的日期选择器会与动态 DOM 发生冲突?

jquery学习:选择器&dom操作

jQuery笔记jQuery选择器

jQuery

jQuery选择器和DOM操作——《锋利的jQuery》(第2版)读书笔记1