话不多说,直接上代码。
父页面 parent.tsx
tsx
import { useRef, useEffect } from 'react'
import authResizeIframeHeight from './authResizeIframeHeight.ts'
const Parent = () => {
const iframeRef = useRef()
useEffect(() => {
authResizeIframeHeight({ iframe: iframeRef.current })
}, [])
return (
<div>
<iframe
src='child.tsx'
ref={iframeRef}
width='100%'
height='100%'
frameBorder={0}
/>
</div>
)
}
export default Parent
其中 authResizeIframeHeight.ts 代码如下:
ts
/**
* 自适应 iframe 高度
* @param iframe 元素
* @returns
*/
export authResizeIframeHeight = ({ iframe }) => {
const MIN_HEIGHT = 800
const MAX_HEIGHT = 3000
const handleMessage = (event) => {
const { source, origin, data } = event
if (!data || typeof data !== 'object' || !origin || !source) {
return
}
const { type, height } = data
const originValid = `${origin}/` === 'http://dev.jd.com'
const sourceValid = source === iframe?.contentWindow
const typeValid = type === 'resize-height'
const heightValid = typeof height === 'number'
if (originValid && sourceValid && typeValid && heightValid) {
let finalHeight = height
if (height < MIN_HEIGHT) {
finalHeight = MIN_HEIGHT
} else if (height > MAX_HEIGHT) {
finalHeight = MAX_HEIGHT
}
iframe.style.height = `${finalHeight}px`
}
}
window.addEventListener('message', handleMessage)
return () => {
window.removeEventListener('message', handleMessage) // 防止内存泄漏
}
}
子页面 child.tsx
tsx
/**
* 自适应 iframe 高度
* @returns
*/
const postMessageResize = () => {
const targetOright = 'http://dev.jd.com';
let lastHeight = 0;
const mo = new MutationObserver(() => {
const currentHeight = document.body.scrollHeight;
if (currentHeight === lastHeight) {
return;
}
lastHeight = currentHeight;
parent.postMessage(
{
type: 'resize-height',
height: currentHeight
},
targetOright
);
});
// 开始监控 body 元素的修改:
mo.observe(document.body, {
attributes: false,
childList: true,
subtree: true
});
};
postMessageResize();
再看看 mutationObserver 的兼容性。

IE11 都支持。
PS:某些交互还需要父页面和子页面共同实现,比如从高度大的页面跳转到高度小的页面时,需要返回顶部。