我编写了一个Tampermonkey脚本,将一些DOM元素注入到我用来工作的站点中,以使导航更加容易。它不再起作用,因为供应商可能已经引入了MutationObserver来阻止像我这样的人这样做。为什么,我不知道。我没有做任何邪恶的事情。
我知道这是正在发生的事情,因为我可以看到我的DOM元素短暂出现然后消失。它们不再位于DOM树中,并且站点的JS包含MutationObservers的代码:
// this is a property of a large object
value: function() {
var e = this
if (this._options.shouldContainFocus) {
this._observer = new MutationObserver(this.handleDOMMutation)
for (var t = this._contextElement; t && 1 === t.nodeType && "BODY" !== t.tagName;) {
var n = t.parentElement
if (n) {
this._parents.push(n)
this.muteNode(n)
Array.prototype.slice.call(n.childNodes).forEach(function(t) {
e.hideNode(t)
})
}
t = t.parentNode
}
}
}
// this is what is called by the MutationObserver
this.handleDOMMutation = function(e) {
e.forEach(function(e) {
Array.from(e.addedNodes).forEach(function(e) {
n.hideNode(e)
})
e.removedNodes.forEach(function(e) {
var t = n._nodes.indexOf(e)
t >= 0 && n._nodes.splice(t, 1)
})
})
}
所以我的问题是……如果有的话,我该如何解决?我所能想到的就是访问一些MutationObservers全局列表,但是从我的阅读来看,这似乎并不存在(直到今天我才听说过此API)。观察者变量不是我可以通过
unsafeWindow
访问的变量,因此无法调用disconnect
方法。我已经阅读了MutationObservers上的文档,但是找不到任何可以帮助我的东西。有什么建议么? 最佳答案
如评论中所述,这是在文档加载之前覆盖window.MutationObserver
的一种可能方法。因为MutationObserver
是作为构造函数调用的,所以为了使网站的脚本不会引发错误,请确保让您的猴子补丁MutationObserver
作为构造函数可调用。然后,由于实例化的对象可以调用其上的方法(如observe
和disconnect
),因此您可以返回Proxy
,当访问属性(如observer
)时,该window.MutationObserver
返回一个可调用的函数。 ,但不执行任何操作。例如:
const div = document.querySelector('div');
window.MutationObserver = function() {
return new Proxy({}, { get: () => () => null })
};
new MutationObserver(() => {
console.log('saw a mutation');
}).observe(div, { childList: true });
div.appendChild(document.createElement('span')).textContent = 'bar';
<div>foo</div>
如果
new MutationObserver
的初始重新分配发生在站点的脚本运行之前,则对window.MutationObserver
的调用将返回不执行任何操作的观察者。 (如您在上面的代码中看到的,如果删除'saw a mutation'
的重新分配,您将看到window.MutationObserver
已记录,而在monkeypatching之后,将不记录任何内容。)因此,将其翻译为用户脚本,粘贴
document-start
重新分配,并确保该用户脚本在MutationObserver
运行,以便该脚本在站点的内置脚本运行之前运行。如果还希望在自己的代码中使用window.MutationObserver
,请在重新分配MutationObserver
之前保存对它的引用:// ==UserScript==
// @name New Userscript
// @match https://somewhere
// @run-at document-start
// ==/UserScript==
const oldMutationObserver = window.MutationObserver;
window.MutationObserver = function() {
return new Proxy({}, { get: () => () => null })
};
如果您所在的站点依赖于
takeRecords()
属性和函数来返回合理的值(例如Proxy
),则与其返回不执行任何操作的MutationObserver
,不如返回一个可以访问实际实例的Proxy observe
的一个元素,当在其上调用时,它观察到另一个元素(一个永不突变的元素):// Userscript code:
const oldMutationObserver = window.MutationObserver;
const elementThatIsNeverMutated = document.createElement('div');
window.MutationObserver = function(callback) { // callback should never be called
const observer = new oldMutationObserver(callback);
return new Proxy(observer, { get: (obj, prop) => {
if (prop === 'observe') return (targetNode, config) => {
obj.observe.call(obj, elementThatIsNeverMutated, config);
};
const val = obj[prop];
return typeof val === 'function' ? val.bind(obj) : val;
}})
};
// Example of site's built-in code:
const div = document.querySelector('div');
const observer = new MutationObserver(() => {
console.log('saw a mutation');
});
observer.observe(div, { childList: true });
div.appendChild(document.createElement('span')).textContent = 'bar';
const arr = observer.takeRecords();
arr.forEach(() => console.log('some item in array'));
<div>foo</div>
关于javascript - 解决现有的MutationObserver以使用Tampermonkey插入DOM元素,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52359715/