本质上,我希望在内容DIV
更改时执行脚本。由于脚本是独立的(Chrome 扩展程序和网页脚本中的内容脚本),我需要一种方法来简单地观察 DOM 状态的变化。我可以设置投票,但这似乎很草率。
是否有 JavaScript / jQuery DOM 更改侦听器?
长期以来,DOM3 突变事件是最好的可用解决方案,但由于性能原因,它们已被弃用。DOM4 Mutation Observers是已弃用的 DOM3 突变事件的替代品。它们目前在现代浏览器中实现为MutationObserver
(或作为WebKitMutationObserver
旧版 Chrome 中的供应商前缀):
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(function(mutations, observer) {
// fired when a mutation occurs
console.log(mutations, observer);
// ...
});
// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
subtree: true,
attributes: true
//...
});
此示例侦听 DOMdocument
及其整个子树的更改,并将触发元素属性的更改以及结构的更改。规范草案有一个完整的有效突变监听器属性列表:
子列表
true
如果要观察目标孩子的突变,则设置为。属性
true
如果要观察目标属性的突变,则设置为。字符数据
true
如果要观察目标数据的突变,则设置为。子树
- 设置为
true
if 突变不仅要观察目标,还要观察目标的后代。属性旧值
- 设置为
true
ifattributes
,设置为true,需要记录突变前target的属性值。字符数据旧值
- 设置为
true
ifcharacterData
设置为 true 并且需要记录突变之前的目标数据。属性过滤器
- 如果不需要观察所有属性突变,则设置为属性本地名称列表(没有命名空间)。
(此列表截至 2014 年 4 月是最新的;您可以查看规范以了解任何更改。)
许多站点使用 AJAX/XHR/fetch 来动态添加、显示、修改内容和 window.history API 而不是站点内导航,因此当前 URL 以编程方式更改。此类站点称为 SPA,单页应用程序的缩写。
检测页面变化的常用JS方法
MutationObserver ( docs ) 从字面上检测 DOM 更改:
简单的例子:
let lastUrl = location.href; new MutationObserver(() => { const url = location.href; if (url !== lastUrl) { lastUrl = url; onUrlChange(); } }).observe(document, {subtree: true, childList: true}); function onUrlChange() { console.log('URL changed!', location.href); }
通过发送 DOM 事件来指示内容更改的站点的事件侦听器:
pjax:end
在document
许多基于 pjax 的站点(例如 GitHub)上使用,
请参阅如何在 pjax 加载之前和之后运行 jQuery?message
上window
使用的Chrome浏览器如谷歌搜索,
看到Chrome扩展检测谷歌搜索刷新yt-navigate-finish
Youtube 使用,
请参阅如何检测 YouTube 上的页面导航并无缝修改其外观?
通过 setInterval 定期检查 DOM:
显然,这仅在您等待由其 id/选择器标识的特定元素出现的情况下才有效,并且除非您发明某种指纹识别,否则它不会让您普遍检测新的动态添加的内容现有的内容。伪装历史API:
let _pushState = History.prototype.pushState; History.prototype.pushState = function (state, title, url) { _pushState.call(this, state, title, url); console.log('URL changed', url) };
监听hashchange , popstate事件:
window.addEventListener('hashchange', e => { console.log('URL hash changed', e); doSomething(); }); window.addEventListener('popstate', e => { console.log('State changed', e); doSomething(); });
PS 所有这些方法都可以在 WebExtension 的内容脚本中使用。这是因为我们正在研究的情况是通过 history.pushState 或 replaceState 更改 URL 的情况,因此页面本身在相同的内容脚本环境下保持不变。
另一种方法取决于您如何更改 div。如果您使用 JQuery 通过其 html() 方法更改 div 的内容,则可以扩展该方法并在每次将 html 放入 div 时调用注册函数。
(function( $, oldHtmlMethod ){
// Override the core html method in the jQuery object.
$.fn.html = function(){
// Execute the original HTML method using the
// augmented arguments collection.
var results = oldHtmlMethod.apply( this, arguments );
com.invisibility.elements.findAndRegisterElements(this);
return results;
};
})( jQuery, jQuery.fn.html );
我们只是拦截对 html() 的调用,用 this 调用一个注册函数,它在上下文中指的是目标元素获取新内容,然后我们将调用传递给原始的 jquery.html() 函数。请记住返回原始 html() 方法的结果,因为 JQuery 期望它用于方法链接。
有关方法覆盖和扩展的更多信息,请查看http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm,这是我写了闭包函数。还可以查看 JQuery 站点上的插件教程。
除了MutationObserver
API提供的“原始”工具之外,还存在处理 DOM 突变的“便利”库。
考虑: MutationObserver 代表子树方面的每个 DOM 更改。因此,例如,如果您正在等待插入某个元素,它可能在mutations.mutation[i].addedNodes[j]
.
另一个问题是,当您自己的代码对突变做出react时,更改了 DOM - 您通常希望将其过滤掉。
一个很好的解决此类问题的便利库是mutation-summary
(免责声明:我不是作者,只是一个满意的用户),它使您能够指定对您感兴趣的内容的查询,并得到准确的结果。
文档中的基本用法示例:
var observer = new MutationSummary({
callback: updateWidgets,
queries: [{
element: '[data-widget]'
}]
});
function updateWidgets(summaries) {
var widgetSummary = summaries[0];
widgetSummary.added.forEach(buildNewWidget);
widgetSummary.removed.forEach(cleanupExistingWidget);
}