Answers:
长期以来,DOM3突变事件是最好的可用解决方案,但由于性能原因,已不推荐使用它们。DOM4突变观察者代替了不推荐使用的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
//...
});
此示例侦听DOM document
及其整个子树上的更改,并将在元素属性更改和结构更改时触发。规范草案包含有效的变异侦听器属性的完整列表:
childList
- 设置为
true
是否要观察目标儿童的突变。属性
- 设置为
true
是否要观察到目标属性的突变。characterData
- 设置为
true
是否要观察到目标数据的变异。子树
- 设置为
true
是否不仅要观察目标,还要观察目标的后代的突变。attributeOldValue
- 设置为
true
if时attributes
将其设置为true,并且需要记录突变之前的目标属性值。characterDataOldValue
- 设置为
true
if如果characterData
设置为true,则需要记录突变之前的目标数据。attributeFilter
- 如果不需要观察所有属性突变,则设置为属性本地名称(无名称空间)的列表。
(此列表是截至2014年4月的最新信息;您可以检查规格中是否有任何更改。)
编辑
现在不赞成使用此答案。见a虫者的答案。
由于这是针对Chrome扩展程序的,因此您最好使用标准DOM事件- DOMSubtreeModified
。请参阅跨浏览器对此事件的支持。从1.0开始,Chrome已支持该功能。
$("#someDiv").bind("DOMSubtreeModified", function() {
alert("tree changed");
});
在这里查看工作示例。
许多站点使用AJAX动态添加/显示/更改内容。有时,它代替现场导航而使用,因此在这种情况下,当前的URL会以编程方式更改,并且内容脚本不会自动由浏览器执行,因为无法完全从远程服务器获取页面。
MutationObserver(docs)从字面上检测DOM更改:
通过发送DOM事件来发出内容更改信号的站点的事件侦听器:
pjax:end
在document
许多基于pjax的网站(例如GitHub)上使用过,message
上window
使用的Chrome浏览器如谷歌搜索,spfdone
在document
YouTube 上使用,通过setInterval进行DOM的定期检查:
显然,这仅在以下情况下有效:当您等待由其ID /选择器标识的特定元素出现时,除非您发明了某种指纹识别方法,否则它不会让您普遍检测到动态添加的新内容。现有内容。
document.head.appendChild(document.createElement('script')).text = '(' +
function() {
// injected DOM script is not a content script anymore,
// it can modify objects and functions of the page
var _pushState = history.pushState;
history.pushState = function(state, title, url) {
_pushState.call(this, state, title, url);
window.dispatchEvent(new CustomEvent('state-changed', {detail: state}));
};
// repeat the above for replaceState too
} + ')(); this.remove();'; // remove the DOM script element
// And here content script listens to our DOM script custom events
window.addEventListener('state-changed', function(e) {
console.log('History state changed', e.detail, location.hash);
doSomething();
});
听hashchange和popstate事件:
window.addEventListener('hashchange', function(e) {
console.log('URL hash changed', e);
doSomething();
});
window.addEventListener('popstate', function(e) {
console.log('State changed', e);
doSomething();
});
有一些用于导航的高级API:webNavigation,webRequest,但是我们将使用简单的chrome.tabs.onUpdated事件侦听器,该消息将消息发送到内容脚本:
background.js
var rxLookfor = /^https?:\/\/(www\.)?google\.(com|\w\w(\.\w\w)?)\/.*?[?#&]q=/;
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (rxLookfor.test(changeInfo.url)) {
chrome.tabs.sendMessage(tabId, 'url-update');
}
});
content.js
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg === 'url-update') {
doSomething();
}
});
另一种方法取决于您如何更改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()的调用,并以此调用一个注册函数,在上下文中它是指目标元素获取新内容,然后将调用传递给原始的jquery.html()函数。记住要返回原始html()方法的结果,因为JQuery希望将其用于方法链接。
有关方法重写和扩展的更多信息,请访问http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm,该文件位于我将闭包函数命名为crisp。还可以在JQuery的站点上查看插件教程。
除了MutationObserver
API提供的“原始”工具外,还存在用于处理DOM突变的“便捷”库。
考虑:MutationObserver用子树表示每个DOM更改。因此,例如,如果您正在等待插入某个元素,则该元素可能位于的子元素内部mutations.mutation[i].addedNodes[j]
。
另一个问题是,当您自己的代码因突变而更改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);
}
([{}])
登录到控制台,MutationRecord
单击该控制台将显示预期的效果。请再次检查,因为这可能是JSFiddle中的暂时性技术故障。我尚未在IE中进行测试,因为我没有IE 10,它是当前唯一支持突变事件的版本。