iframe是HTML中的一个标签,用于当前页面嵌入另一个页面或者当前项目嵌入另一个项目。常见用于第三方内容嵌入(如地图、视频、广告)、多系统集成(如主项目嵌套子项目)等场景。
一、关键属性
| 属性 | 作用 | 适用场景 |
|---|---|---|
src/ srcdoc | src嵌入外部 URL;srcdoc 直接嵌入 HTML 代码 | 子项目部署在独立域名时用 src; 本地静态内容用 srcdoc |
sandbox | 限制 iframe 内页面的权限(如禁止脚本、表单提交) | 提升安全性,防止子项目篡改主项目,例:sandbox="allow-scripts allow-same-origin" |
allowfullscreen | 允许 iframe 内页面触发全屏 | 解决子项目全屏按钮无效的问题 |
loading="lazy" | 懒加载 iframe,提升主页面加载速度 | 非首屏的子项目嵌入 |
referrerpolicy | 控制 iframe 发送的 Referrer 信息 | 跨域场景下的权限控制 |
二、主项目和子项目通信
由于浏览器的同源策略限制,跨域 iframe 通信需通过 postMessage API 实现,这是 iframe 集成的核心方案。
1. 同源通信(主、子项目同域名)
// 主项目获取 iframe 内的 window 对象
const iframeWindow = document.getElementById('myIframe').contentWindow;
// 调用子项目的方法
iframeWindow.childFn();
// 子项目调用主项目的方法
window.parent.parentFn();
2. 跨域通信(主、子项目不同域名)
跨域时必须用 postMessage 实现双向通信:
主项目向子项目发送消息
// 主项目代码
const iframeUrl = 'http://localhost:5174'
const initData = {
name: '父页面初始化数据',
age: 18,
innerData: {
a: 1,
b: 2
}
}
onMounted(() => {
const iframe = document.getElementById('iframeId');
if (iframe) {
iframe.onload = () => {
iframe.contentWindow.postMessage(
{ type: 'INIT', data: initData },
iframeUrl
);
console.log('已发送消息到 iframe');
};
} else {
console.log('没有找到元素');
}
});
// 监听 iframe 回复
onMounted(() => {
window.addEventListener('message', (e) => {
if (e.origin !== iframeUrl) {
//console.log('origin 不匹配,忽略消息')
return
}
console.log('收到子项目的回复:', e.data)
})
})
子项目向主项目发送消息
// 子项目代码
onMounted(() => {
console.log('子应用已挂载,开始监听消息')
const parentOrigin = 'http://localhost:5173'
window.addEventListener('message', (e) => {
if (e.origin !== parentOrigin) {
console.log('origin 不匹配,忽略消息')
return
}
console.log('收到父页面消息:', e.data);
// 回复父页面
if (e.source) {
e.source.postMessage('给主项目回复消息', e.origin)
console.log('已回复父页面')
}
})
console.log('子应用消息监听器已设置')
})
// 主动向父页面发消息
function sendToParent() {
window.parent.postMessage(
{ type: 'REQUEST', data: '请求数据' },
parentOrigin
)
console.log('已主动向父页面发送消息')
}
三、全屏功能实现
子项目内触发全屏时,需同时满足两个条件:
1、iframe 添加 allowfullscreen 属性
子项目内的全屏代码需基于自身 document
// 子项目全屏按钮点击事件
document.getElementById('fullscreenBtn').addEventListener('click', () => {
const docEl = document.documentElement;
if (docEl.requestFullscreen) {
docEl.requestFullscreen();
}
});
五、样式问题
iframe 是独立的 BOM/DOM 环境,默认不会与主项目样式冲突,但需注意以下两点:
1、消除 iframe 自带边框:用 CSS 替代 frameborder 属性
iframe {
border: none;
width: 100%;
height: 100%;
}