Javascript MutationObserver回调未在Firefox中调用,但在Chrome中调用

Javascript MutationObserver回调未在Firefox中调用,但在Chrome中调用,javascript,dom,firefox,iframe,mutation-observers,Javascript,Dom,Firefox,Iframe,Mutation Observers,我有一个问题: 我寻找的每一个资源都告诉我这应该是可行的,在Chrome、Safari中也是如此。。但不是在Firefox中 系统:macOS Catalina 10.15.7、Chrome 90.0.4430.212、Firefox 88.0.1、Edge 90.0.818.66 我试图在Chrome上实现/已经实现的目标是:找到一个iFrame,它托管在同一个域上,并针对其中的一些子节点,更改属性,删除文本输入等 我的JS代码的简化版本: // set as null first b

我有一个问题:

我寻找的每一个资源都告诉我这应该是可行的,在Chrome、Safari中也是如此。。但不是在Firefox中

系统:macOS Catalina 10.15.7、Chrome 90.0.4430.212、Firefox 88.0.1、Edge 90.0.818.66

我试图在Chrome上实现/已经实现的目标是:找到一个iFrame,它托管在同一个域上,并针对其中的一些子节点,更改属性,删除文本输入等

我的JS代码的简化版本:

    // set as null first because the iFrame takes some time to load
    let iframeBody = null;

    // this function is only run once, while it should be run on every MutationObserver change
    function purge (iframe) {

        var timer = null;
        // only by querying that iFrame again Firefox picked up the purge function, I don't need that for Chrome 
        let iF = document.querySelector('#chatbot iframe').contentWindow.document.body;
        var inputField = iF.querySelector('div > div.frame-content > div.widget-position-right > div.chat > div.input-group');
        if(!inputField || typeof inputField === 'undefined') {
          if(timer !== null) {
            clearTimeout(timer);
          }
          timer = setTimeout(purge, 50);
          return;
        }
        // remove it
        inputField.remove();
    }

    // this one is never called in FF
    function cb (mutationList) {
        let chatDiv = iframeBody.querySelector('div > div.frame-content > div.widget-position-right > div.chat')
        if (chatDiv) {
            mutationList.some(item => {
                if (item.type === 'childList' && item.addedNodes && item.addedNodes[0] === chatDiv) {
                    purge();
                    return true;
                }
            })
        }

        let button = iframeBody.querySelector("div > div.frame-content > div.widget-position-right > #button")
    // make button invisible if found, restore if chat is closed
        if (button) {
            if (button.classList.contains('chat-open')) {
                button.style.opacity = 0;
                button.style.pointerEvents = "none";
                button.style.width = 0;
            }
            else {
                button.style.opacity = 1;
                button.style.pointerEvents = "auto";
                button.style.width = "auto";
            }
        }
    }

    function bind () {
        try {
            iframeBody = document.querySelector('#chatbot iframe').contentWindow.document.body;
        
            if (!iframeBody) {
                return setTimeout(bind, 500) // wait and retry because iFrame is not loaded immediately
            }
            if(iframeBody){
                console.log("iframeBody found");
            }

            const mutationObservable = new MutationObserver(cb)

            // actually don't need characterData, just an attempt to pick up the observed event
            const config = { characterData: true, attributes: true, childList: true, subtree: true};

            setTimeout(() => {
                // this is the initial call that works in FF (and Chrome/Safari naturally)
                purge();
                mutationObservable.observe(iframeBody, config);
            }, 500);
            
        } catch (err) {
            // console.log(err);
            // try to bind again, can take some time to load
            setTimeout(bind, 100)
        }
    }
    // start here
    bind();

})();

我验证了我可以在开发人员控制台中使用querySelector访问HTML节点,并在所有浏览器中对它们进行编辑,只是没有拾取MutationObserver回调

我试着这样写

new MutationObserver((mutation) => {
    // cb function goes here
})
但是没有用。我已经为此坐了几个小时了,只是想让它工作起来,我很想为Firefox一起停用它

任何提示都非常感谢。如果需要任何额外的资源,请告诉我

更新:通过如下方式调用MutationObserver(不做任何更改),尝试使用
新建framelem.contentWindow.MutationObserver从评论中提出建议:

const iframeElmWindow = document.querySelector('#chatbot iframe').contentWindow;
const mutationObservable = new iframeElmWindow.MutationObserver(cb);

问题当然是,您在
iframeBody
变量中捕获了初始
about:blank
文档的

这表明您的代码可能捕获初始文档,而不是稍后加载的文档

// removed a lot of unrelated stuff from OP,
// to keep only the core of the issue
function bind() {
  const iframeBody = frame.contentWindow.document.body;
  if( !iframeBody ) {
    return setTimeout( bind, 500 );
  }
  if( iframeBody ) {
    console.log( "iframeBody found" );
    console.log( "location:", iframeBody.ownerDocument.location.href );
                // logs "about:blank"
}
bind();
因此,您正在观察的
就是临时的初始
关于:空白的
文档。由于这个文档将在几毫秒内被加载的文档替换,因此不会发生新的变异

最简单的解决方法是使用
load
事件,该事件仅在加载的文档实际加载时触发。
通过这种方式,您可以确保不会捕获初始的
about:blank
文档,并且不再需要
setTimeout(bind)
hack:在这种情况下,如果您无法访问iframe的
contentDocument
,这是因为这两个上下文不是同一来源,再次尝试也无法修复它

总之,要启动一个针对您的
身体的突变观察者,您需要:

frame.onload = function( evt ) {
  const iframeBody = frame.contentDocument?.body;
  if( !iframeBody ) {
    // this means we are in a cross-origin document...
    return;
  }
  const observer = new MutationObserver( cb );
  observer.observe( iframeBody, { childList: true, subtree: true } );
};
再一次1


一,。我们需要外包这些示例,因为StackSnippet的空源iframe不允许我们的脚本访问iframe的内容,无论它是如何提供的。

您是否可以创建一个您的代码,如果可能的话,可以创建一个StackSnippet。在firefox上试一试它能工作吗?1)试一试
新建framelem.contentWindow.MutationObserver
。2) 跨浏览器无法保证div存在于单独突变的第一个添加节点中,它可能在其他元素中。@wOxxOm 1)我尝试过,但没有看到任何变化,因为2)这是什么意思?我之前只使用div.className或#buttonId定义了它,没有父元素>子元素语法