Javascript 如何断开匿名MutationObserver与文档元素的连接,而不使用其克隆替换元素?

Javascript 如何断开匿名MutationObserver与文档元素的连接,而不使用其克隆替换元素?,javascript,mutation-observers,Javascript,Mutation Observers,在创建一个应该更改多个文档元素属性的tampermonkey脚本时,我遇到了一个使用事件侦听器阻止对该属性进行任何更改的站点。为了对抗这种行为,我可以将元素替换为它们的克隆,如下所示: const map = new Map(); function read() { for (let image of [...document.getElementsByTagName('img')]) { const clone = image.cloneNode(/* with ch

在创建一个应该更改多个文档元素属性的tampermonkey脚本时,我遇到了一个使用事件侦听器阻止对该属性进行任何更改的站点。为了对抗这种行为,我可以将元素替换为它们的克隆,如下所示:

const map = new Map();

function read() {
    for (let image of [...document.getElementsByTagName('img')]) {
        const clone = image.cloneNode(/* with children */true);
        // TODO: modify the clone
        map.set(image, clone);
    }
}

read();

function write() {
    for (let [image, clone] of map) {
        image.parentNode.replaceChild(clone, image);
    }
}

write();

map.clear();
但使用这种方法存在一个问题:浏览器(Chrome71)在操作结束时会重新计算样式,如果元素数量较大(10个元素-无抖动,100个元素-抖动),有时会抖动布局。我尝试使用请求的动画帧修改写入循环函数:

window.requestAnimationFrame(document.replaceChild.bind(image.parentNode, clone, image));
但它仍然会破坏布局。 尝试在循环中插入暂停:

async function write() {
  for (let [image, clone] of map) {
    await new Promise(window.requestAnimationFrame);
    image.parentNode.replaceChild(clone, image);
  }
}
没有变化。试图将数组中的元素分割成小块并操作每个块,但浏览器最终仍然懒散地重新计算样式并重击布局。 因此,我可以使用以下内容删除每个事件侦听器,而不是用克隆替换每个元素:

for (let image of [...document.getElementsByTagName('img')]) {
  const listeners = getEventListeners(image);
  for (let event_type in listeners) {
    for (let event of listeners[event_type]) {
      image.removeEventListener(event.type, event.listener, event.useCapture);
    }
  }
}
虽然这解决了问题,但仍然存在一个问题:如果站点使用的不是事件侦听器,而是MutationObserver来防止修改文档元素,该怎么办?有没有一种方法可以删除MutationObserver而不使用其克隆替换文档元素


虽然我知道修改很多元素的属性仍然会迫使浏览器重新流,但我的问题仍然存在。

没有办法断开anonymous MutationObserver,但这并不意味着没有其他解决方案

我相信您不需要更改页面上的所有链接。
你只需要截取一个用户试图跟随的链接

请参阅下面的代码片段

我们想要更改
href
属性,并且观察者正在捕获该属性:

//匿名观察者:
(新的MutationObserver(函数)(mutationsList,observer){
for(突变列表的var突变){
如果(
突变类型=='attributes'&&
mutation.target.href!=='https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png'
) {
log('修改了'+mutation.attributeName+'属性');
mutation.target.href=https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png'
}
}
}))
.观察(
document.querySelector('html'){
属性:正确,
子树:真
}
);
document.querySelectorAll('a').forEach(函数(a){
a、 href='https://yastatic.net/www/_/x/Q/xk8YidkhGjIGOrFm_dL5781YA.svg';
});

没有这样的方法。另外请注意,该站点还可以使用IntersectionObserver或哑间隔检查检测从DOM中删除的元素,然后重新附加到新元素。更具体地说,您在谈论什么网站?最后你想做什么?@wOxxOm,谢谢。请注意。@KoshVery,所讨论的站点是。Tampermonkey脚本正在修改链接/锚标记的href,这样我就可以跳过链接处理程序(如steam链接过滤器),直接进入理想的站点。谢谢在不克隆链接标记的情况下,绕过link href属性上的observer确实是一种解决方案。但有两个细节让我感到不舒服:在每个新链接的无限滚动页面上都会有新的侦听器(我的计算机不会爆炸吗?),用户不能在悬停时预览url(这不是很糟糕吗?)。另外,虽然您的回答很有用,但我不知道是否应该标记我的问题已回答,“因为据我所知,无法断开document元素上的匿名MutationObserver?”即“sme-还有谁,谢谢您的留言!我已经更新了我的答案来明确回答你的问题——如果是匿名的,你不能断开它。关于无限滚动,如果您对加载无限内容感到满意,也不用担心事件侦听器=))认真地说,您可以设置一个委托的
touchstart/mousedown
侦听器,然后在其回调集
中单击
侦听器--您可能会节省一些内存。第二,用户不能在悬停时预览url——这也是可以解决的,但超出了这个问题的范围。