iframe 的优缺点与通信
iframe 的使用场景、优缺点分析及跨域通信方案
问题
分析 iframe 的优缺点,以及如何实现 iframe 与父页面之间的通信。
解答
优点
- 隔离性强:iframe 内容与主页面完全隔离,CSS 和 JavaScript 互不影响
- 嵌入第三方内容:方便嵌入广告、视频、地图等第三方服务
- 并行加载:iframe 可以与主页面并行加载资源
- 独立沙箱:可用于运行不可信代码,提供安全隔离环境
缺点
- SEO 不友好:搜索引擎难以抓取 iframe 内容
- 阻塞主页面 onload:iframe 加载会阻塞父页面的 onload 事件
- 性能开销:每个 iframe 都是独立的文档环境,消耗更多内存
- 用户体验差:浏览器后退按钮行为不符合预期
- 响应式困难:iframe 高度自适应需要额外处理
通信方式
1. 同域通信
同域下可以直接访问对方的 window 对象:
// 父页面访问 iframe
const iframe = document.getElementById('myIframe');
const iframeWindow = iframe.contentWindow;
const iframeDocument = iframe.contentDocument;
// 调用 iframe 内的函数
iframeWindow.childFunction();
// iframe 访问父页面
window.parent.parentFunction();
// 访问顶层窗口
window.top.topFunction();
2. 跨域通信 - postMessage
跨域场景必须使用 postMessage:
// 父页面发送消息
const iframe = document.getElementById('myIframe');
iframe.onload = function() {
iframe.contentWindow.postMessage(
{ type: 'greeting', data: 'Hello from parent' },
'https://child.example.com' // 指定目标源,不要用 '*'
);
};
// 父页面接收消息
window.addEventListener('message', function(event) {
// 验证消息来源
if (event.origin !== 'https://child.example.com') {
return;
}
console.log('收到消息:', event.data);
});
// iframe 子页面发送消息
window.parent.postMessage(
{ type: 'response', data: 'Hello from child' },
'https://parent.example.com'
);
// iframe 子页面接收消息
window.addEventListener('message', function(event) {
// 验证消息来源
if (event.origin !== 'https://parent.example.com') {
return;
}
console.log('收到消息:', event.data);
});
3. 完整通信示例
<!-- 父页面 parent.html -->
<!DOCTYPE html>
<html>
<body>
<button id="sendBtn">发送消息</button>
<iframe id="childFrame" src="https://child.example.com/child.html"></iframe>
<script>
const iframe = document.getElementById('childFrame');
const targetOrigin = 'https://child.example.com';
// 发送消息
document.getElementById('sendBtn').onclick = function() {
iframe.contentWindow.postMessage({
type: 'UPDATE_DATA',
payload: { count: 100 }
}, targetOrigin);
};
// 接收消息
window.addEventListener('message', function(event) {
if (event.origin !== targetOrigin) return;
if (event.data.type === 'DATA_RECEIVED') {
console.log('子页面确认收到:', event.data.payload);
}
});
</script>
</body>
</html>
<!-- 子页面 child.html -->
<!DOCTYPE html>
<html>
<body>
<script>
const parentOrigin = 'https://parent.example.com';
window.addEventListener('message', function(event) {
if (event.origin !== parentOrigin) return;
if (event.data.type === 'UPDATE_DATA') {
console.log('收到数据:', event.data.payload);
// 回复确认消息
event.source.postMessage({
type: 'DATA_RECEIVED',
payload: { success: true }
}, event.origin);
}
});
</script>
</body>
</html>
关键点
- 同域可直接通过
contentWindow、parent、top访问 - 跨域必须使用
postMessage,且要验证event.origin postMessage第二个参数指定目标源,生产环境不要用'*'- iframe 会阻塞主页面 onload,可用动态创建或
loading="lazy"优化 - 现代开发中,微前端方案(如 qiankun)逐渐替代 iframe 的部分场景
目录