如何防止隐藏和显示 iframe 的 MutationObserver 闪烁

How to prevent hide and show flickering of MutationObserver for iframe

我正在开发 chrome 隐藏文章的扩展 MV3。

MutationObserver 隐藏文章而不在主框架闪烁。

例如,下面的代码在有新文章时通过向下滚动将 odd 的文章隐藏在 Reddit

function eraseDealer(){
    console.log("erase Function Call");
    let ls = document.querySelectorAll('#SHORTCUT_FOCUSABLE_DIV > div:nth-child(4) > div > div > div > div._3ozFtOe6WpJEMUtxDOIvtU > div._31N0dvxfpsO6Ur5AKx4O5d > div._1OVBBWLtHoSPfGCRaPzpTf._2OVNlZuUd8L9v0yVECZ2iA > div.rpBJOHq2PR60pnwJlUyP0 > div');
    let idx;

    for(idx=ls.length-1; idx>=0; idx--){
        if(idx%2===0) continue
        ls[idx].setAttribute('style', 'display: none;');
    }
}

eraseDealer();

var config = { childList: true, characterData: false };
var htmlBody = document.getElementsByClassName('rpBJOHq2PR60pnwJlUyP0')[0];

var observerErase = new MutationObserver(function(mutations, observer) {
    mutations.forEach(function(mutation) {
        console.log("Mutation call - erase");
        eraseDealer();

    });
});

observerErase.observe(htmlBody, config);

但是如果MutationObserver(in main frame) observe article(in iframe),就会出现闪烁(先显示文章,再隐藏文章)

下面的代码适用于 Korea community site,代码的作用与上面的代码类似。

loom

查看它的工作原理
function eraseDealer(){
    let inner_iframe = document.getElementById('cafe_main').contentWindow;
    let post_table = inner_iframe.document.querySelectorAll('#main-area > div.article-board.m-tcol-c')[1];
    if(post_table !== undefined){
        let ls = post_table.querySelectorAll('div.article-board.m-tcol-c > table > tbody > tr');

        let idx;
        let dealer_link = 'https://cafe.pstatic.net/levelicon/1/1_150.gif';

        for(idx=ls.length-1; idx>=0; idx--){
            let src = ls[idx].querySelector('td.td_name > div > table > tbody > tr > td > span > img').getAttribute('src');
            let nickName = ls[idx].querySelector('td.td_name > div > table > tbody > tr > td > a').textContent;
            if(src === dealer_link){
                ls[idx].setAttribute('style', 'display: none;');
            }
        }
    }
}

eraseDealer();

var config = { attributes: true, childList: true, subtree: true, characterData: false };
var target = document.querySelector('#main-area');

var observerErase = new MutationObserver(function(mutations, observer) {
    mutations.forEach(function(mutation) {
        console.log("Mutation call - erase");
        eraseDealer();
    });
});

observerErase.observe(target, config);

为什么我不在 iframe 中而是在主框架中插入 mutationObserver 是当 iframe url 更改时 mutationObserver 被删除

看到关注这个

是否有任何MutationObserver 属性需要停止与iframe有关的闪烁?

我用 Whosebug 和 chrome 文档搜索了很多,但找不到解决方案

您可以检测 iframe 在内部导航的时刻,而不是主文档中的 MutationObserver,然后为 iframe 的内容添加 MutationObserver。

  1. checkFrameReady 侦听器将 运行 在 iframe 的 URL 更改之后,但在其导航完成之前。
  2. 在此期间,DOMException 将在侦听器尝试启动观察器时不断在内部发生。
  3. 侦听器将通过 requestAnimationFrame 重复自身,直到 iframe 最终完成导航到新 URL。在那一刻,iframe 与主页成为同源,我们的代码将能够访问 iframe 的内容并启动观察者。
var SEL = '.td_name img[src="https://cafe.pstatic.net/levelicon/1/1_150.gif"]';
var fw = document.querySelector('#cafe_main').contentWindow;
fw.addEventListener('unload', checkFrameReady);

function checkFrameReady(e) {
  if (!e.type) {
    try {
      startObserver(new fw.MutationObserver(eraseDealer));
      fw.addEventListener('unload', checkFrameReady);
      return;
    } catch (e) {}
  }
  requestAnimationFrame(checkFrameReady);
}
function eraseDealer(mutations, observer) {
  let stopped;
  for (const { addedNodes } of mutations) {
    for (const n of addedNodes) {
      if (!n.tagName) continue;
      const elems = n.matches(SEL) && [n] ||
        n.firstElementChild && n.querySelectorAll(SEL);
      if (!elems || !elems.length) continue;
      if (!stopped) { stopped = true; observer.disconnect(); }
      elems.forEach(el => el.closest('.td_name').closest('tr').remove());
    }
  }
  if (stopped) startObserver(observer);
}
function startObserver(observer) {
  observer.observe(fw.document.body || fw.document.documentElement,
    {childList: true, subtree: true});
}