如何让 A 页面的宽高实时自适应 iframe 的宽高大小

一个 iframe,内嵌了一个 A 页面,iframe 的宽高不停变化,如何让 A 页面的宽高实时自适应这个 iframe 的宽高大小。请说出至少 3 种方法,越难越好。

参考答案:

补充

补充:让嵌入的 A 页面跟随外层 iframe 宽高自适应,本质是父页面把尺寸告诉子页面或子页面主动监听父页面尺寸。下面给出 3 种由易到难的方法。

方法一:CSS 设置 100% 宽高(最简单)

如果 A 页面就是普通 HTML,让它的根元素始终占满父容器即可:

/* A 页面 */
html, body {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}

外层 iframe 改变宽高后,A 页面也会跟着撑满。缺点:只解决"铺满",解决不了 A 内部布局自适应。

方法二:postMessage 跨域通信(推荐)

父子之间通过 postMessage 传递尺寸,父页面在 onresize 时把新尺寸发给子页面。

父页面(host):

const iframe = document.getElementById('myFrame');

function sendSize() {
  iframe.contentWindow.postMessage({
    type: 'resize',
    width: iframe.clientWidth,
    height: iframe.clientHeight,
  }, '*'); // 生产环境换成具体 origin
}

window.addEventListener('resize', sendSize);
iframe.addEventListener('load', sendSize);

子页面(A):

window.addEventListener('message', (e) => {
  if (e.data && e.data.type === 'resize') {
    document.documentElement.style.width = e.data.width + 'px';
    document.documentElement.style.height = e.data.height + 'px';
    // 触发内部布局重新计算
    window.dispatchEvent(new Event('resize'));
  }
});

注意跨域时 postMessage 的第二个参数应当是具体 origin,而不是 '*'。

方法三:同域下用 window.frameElement(最直接)

如果 A 页面与父页面同源,A 页面可以直接读取包裹它的 iframe 的尺寸:

function syncSize() {
  const frame = window.frameElement; // 当前页面所在 iframe 元素
  if (frame) {
    document.documentElement.style.width = frame.clientWidth + 'px';
    document.documentElement.style.height = frame.clientHeight + 'px';
  }
}

syncSize();
window.addEventListener('resize', syncSize);

方法四(额外):父页面动态设置 iframe 高度以适应内容

反过来,如果要让 iframe 高度跟着 A 内容自适应,可以让 A 把自身高度通过 postMessage 告诉父页面,父页面再去改 iframe.style.height。

来源整理自:我的有道云笔记