流程
- 流程梳理: [https://juejin.cn/editor/drafts/7368316813711556608](url)
难点一:iframe中页面执行时按钮的抓取
- 因为项目结构比较复杂,进入页面后也有pageloadding很多页面相应影响的问题,所以这里就加了定时器一 直监听到相应改变,确保能抓到按钮的位置从而确保事件的执行
observeButtons(iframeDocument) {
const observer = new MutationObserver((mutations) => {
const innerIframe = iframeDocument.getElementById("headerIframe");
if (innerIframe) {
innerIframe.onload = () => {
const innerIframeDocument = innerIframe.contentDocument || innerIframe.contentWindow.document;
const checkButtons = () => {
const buttons = Array.from(innerIframeDocument.querySelectorAll("button"));
buttons.forEach((button) => {
const buttonText = button.textContent.trim();
if (buttonText === "进入办事" && button.closest("#recept-footer-Notice")) {
button.addEventListener("click", () =>
this.handleButtonClick(buttonText, innerIframeDocument)
);
console.log("进入办事按钮事件监听器已添加。");
observer.disconnect(); // 断开 MutationObserver
} else if (buttonText === "确 定" && button.closest("#recept-footer-SceneGuide")) {
button.addEventListener("click", () =>
this.handleButtonClick(buttonText, innerIframeDocument)
);
console.log("确定按钮事件监听器已添加。");
observer.disconnect(); // 断开 MutationObserver
} else if (buttonText === "下一步" && button.closest("#recept-footer-Form")) {
button.addEventListener("click", () =>
this.handleButtonClick(buttonText, innerIframeDocument)
);
console.log("下一步按钮事件监听器已添加。");
observer.disconnect(); // 断开 MutationObserver
} else {
console.log("按钮未找到,继续检查...");
}
});
setTimeout(checkButtons, 500); // 每隔500ms检查一次
};
checkButtons();
};
} else {
console.log("未找到内部 iframe,继续检查...");
}
});
const config = { childList: true, subtree: true };
observer.observe(iframeDocument, config);
},
embedScriptInIframe() {
const iframe = this.$refs.aio_if;
// 等待 iframe 加载完成
iframe.onload = () => {
const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
// 创建一个 script 标签
const script = iframeDocument.createElement("script");
script.src = "https://oss-fsx.oss-cn-hangzhou.aliyuncs.com/terminal/inject.js"; // 确保路径正确
script.type = "text/javascript";
// 将 script 标签添加到 iframe 的 head 中
iframeDocument.head.appendChild(script);
// 验证脚本是否已加载
script.onload = () => {
console.log("global.js 已加载");
callFlineJSAPI("init", "1", null, null);
setTimeout(() => {
this.observeButtons(iframeDocument);
if (iframe.contentWindow.myGlobalFunction) {
console.log("myGlobalFunction 已定义");
} else {
console.error("myGlobalFunction 未定义");
}
}, 1000); // 延迟检查,确保脚本完全执行
};
script.onerror = () => {
console.error("global.js 加载失败");
};
};
},
MutationObserver
MutationObserver是DOM Level 4规范中引入的一个功能,它提供了一种方式,可以监视DOM树中的变化,并作出相应的反应。这种变化可以是属性的变化、节点的添加或移除、文本内容的改变等。
以下是一个MutationObserver的基本使用示例:
- 创建MutationObserver实例:
首先,你需要创建一个
MutationObserver的实例,并且传入一个回调函数,这个回调函数会在每次DOM发生变化时被调用。 - 配置观察选项: 然后,你需要定义一个配置对象,指定你想要观察的DOM变化类型,比如子节点的变化、属性的变化等。
- 开始观察:
使用
observe方法,你可以开始观察一个特定的DOM节点。 - 处理变化:
当DOM发生变化时,
MutationObserver会调用你提供的回调函数,并传入一个包含所有变化的MutationRecord对象的数组。 - 停止观察:
如果需要,你可以调用
disconnect方法来停止观察。 下面是一个简单的例子,展示了如何使用MutationObserver来观察一个元素的内容变化:
// 创建MutationObserver实例
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
console.log('A child node has been added or removed.');
} else if (mutation.type === 'attributes') {
console.log('The ' + mutation.attributeName + ' attribute has been changed.');
}
});
});
// 配置观察选项
var config = { attributes: true, childList: true, subtree: true };
// 开始观察目标节点
var targetNode = document.getElementById('some-id');
observer.observe(targetNode, config);
// 停止观察
// observer.disconnect();
在这个例子中,我们创建了一个MutationObserver实例,并且配置了它来观察目标节点的子节点变化和属性变化。当这些变化发生时,控制台会打印出相应的信息。如果你想停止观察,可以调用observer.disconnect()。
MutationObserver是一个强大的工具,可以用于许多场景,比如实现自动化的单元测试、动态内容加载、无刷新页面更新等。
1. 自动化的单元测试
在自动化单元测试中,MutationObserver可以用来检测DOM是否按照预期发生了变化。
function simulateClick(element) {
// 模拟点击事件
var event = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
element.dispatchEvent(event);
}
function testDOMChange() {
return new Promise(function(resolve, reject) {
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length) {
// 检测到节点添加,假设这是期望的行为
observer.disconnect();
resolve();
}
});
});
var target = document.body;
observer.observe(target, { childList: true });
// 模拟用户行为,比如点击一个按钮
var button = document.getElementById('my-button');
simulateClick(button);
});
}
// 使用测试框架的API来运行测试
test('DOM change on button click', function(assert) {
return testDOMChange().then(function() {
assert.ok(true, 'DOM changed as expected');
});
});
在这个例子中,我们创建了一个MutationObserver来观察document.body的子节点变化。然后,我们模拟了一个点击事件,如果点击导致了期望的DOM变化(比如添加了新的节点),那么测试就会通过。
2. 动态内容加载
在动态内容加载中,MutationObserver可以用来检测何时新内容被添加到DOM中,并据此触发特定的逻辑。
function handleContentLoad(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length) {
// 新节点被添加,可以执行相关逻辑,比如初始化新添加的组件
mutation.addedNodes.forEach(function(node) {
if (node.tagName === 'DIV' && node.classList.contains('new-content')) {
initializeNewContent(node);
}
});
}
});
}
var observer = new MutationObserver(handleContentLoad);
observer.observe(document.body, { childList: true, subtree: true });
function initializeNewContent(node) {
// 初始化新内容的逻辑
console.log('New content initialized:', node);
}
在这个例子中,我们设置了一个MutationObserver来观察整个文档树的子节点变化。当有新内容被添加到DOM中时,handleContentLoad函数会被调用,我们可以在这里初始化新添加的内容。
3. 无刷新页面更新
在无刷新页面更新(也称为SPA中的“页面切换”)中,MutationObserver可以用来检测页面部分的改变,并相应地更新页面状态。
function handlePageChange(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
// 检测到页面内容的改变,更新页面状态
updatePageState();
}
});
}
var observer = new MutationObserver(handlePageChange);
var target = document.getElementById('page-content');
observer.observe(target, { childList: true });
function updatePageState() {
// 更新页面状态的逻辑,比如更新URL、激活导航菜单等
console.log('Page state updated.');
}
在这个例子中,我们创建了一个MutationObserver来观察ID为page-content的元素。当这个元素的子节点发生变化时,我们假设页面内容已经更新,然后调用updatePageState函数来更新页面的状态。
这些例子展示了MutationObserver在不同场景下的应用方式,它提供了一种灵活且强大的机制来响应DOM的变化。