Javascript MutationObserver回调未在Firefox中调用,但在Chrome中调用
我有一个问题: 我寻找的每一个资源都告诉我这应该是可行的,在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代码的简化版本: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
// 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定义了它,没有父元素>子元素语法