iframe

67 阅读2分钟

iframe是HTML中的一个标签,用于当前页面嵌入另一个页面或者当前项目嵌入另一个项目。常见用于第三方内容嵌入(如地图、视频、广告)、多系统集成(如主项目嵌套子项目)等场景。

一、关键属性

属性作用适用场景
src/ srcdocsrc嵌入外部 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%;
}