const observer = new MutationObserver ( () => { const contentHeight = content. scrollHeight ; console . log ( 'contentHeight' , contentHeight) window . parent . postMessage ({ height : contentHeight }, '*' ); observer. observe (content, { childList : true , subtree : true }); window . addEventListener ( 'load' , observeContentHeight); </ script >
class XXX extends PureComponent {
  constructor(props) {
    super(props);
    this.iframeRef = React.createRef();
  componentDidMount() {
    window.addEventListener('message', this.handleMessage);
  componentWillUnmount() {
    window.removeEventListener('message', this.handleMessage);
  handleMessage = (event) => {
    console.log(event)
    if (event.data && event.data.height) {
      const iframeHeight = event.data.height;
      const iframe = this.iframeRef.current;
      if (iframe) {
        iframe.style.height = `${iframeHeight}px`;
  render() {
    return (
      <PageHeaderWrapper>
          <iframe
            src='xxx.url.com'
            ref={this.iframeRef}
            onLoad={this.adjustIframeHeight}
      </PageHeaderWrapper>

子页面内使用MutationObserver来监听页面内容的变化,并在变化时通过postMessage将页面加载完成后的高度发送给父页面。

首先创建一个MutationObserver对象,用于监听子页面内容的变化。在这个例子中,将content设为的目标,并传入配置对象{ childList: true, subtree: true },表示要观察子节点的添加或删除,以及整个子树的变化。

在本例中,使用了以下配置对象:{ childList: true, subtree: true }

  • childList:表示要观察目标节点的子节点的变化。当子节点被添加或删除时,MutationObserver会触发回调函数。如果将childList设置为true,则会观察子节点的变化;如果设置为false,则不会观察子节点的变化。
    2.subtree:表示我们要观察目标节点的整个子树的变化。当目标节点及其后代节点的属性或子节点发生变化时,MutationObserver会触发回调函数。如果将subtree设置为true,则会观察整个子树的变化;如果设置为false,则只会观察目标节点本身的变化。
  • 从而,当页面路由变化等情况发生时,页面内容的高度同时产生变化,并调用回调函数,获取到最新的页面高度content.scrollHeight

    最后使用window.parent.postMessage方法向父页面发送消息。配置中的'*'表示会将消息发送给所有的父页面,即使不在同一域中。

    父页面主要逻辑是在组件挂载时监听message事件,接收来自iframe的消息,并根据消息中的高度调整iframe的高度。在组件挂载时,通过window.addEventListener方法监听message事件,以便接收来自iframe的消息。在组件卸载时,通过window.removeEventListener方法移除对message事件的监听,以避免内存泄漏。

    通过监听message事件,可以实时接收来自iframe的消息,并根据消息中的高度调整iframe的高度。这样可以确保iframe的高度始终与其内容的高度保持一致,避免出现滚动条或内容被截断的问题。

    postMessage与跨域

    在Web开发中,浏览器实施了同源策略(Same-Origin Policy),该策略限制了不同源(协议、域名、端口)之间的交互。这意味着在一个页面中的JS代码无法直接访问来自不同源的页面的内容或执行操作。在本项目中,由于嵌入的iframe域名与父页面域名不同,触发了同源策略,导致直接通过JS获取子页面高度的方法失效。

    在iframe跨域传参的情况下,父页面和子页面属于不同的源,无法直接访问对方的内容。因此需要使用postMessage来进行跨域通信,它允许在不同窗口或标签页之间进行安全的跨域通信。通过在父页面中向子页面发送消息,或在子页面中向父页面发送消息,来实现参数的传递和交互。postMessage的跨窗口的通信方式可以绕过同源策略的限制,实现不同源页面之间的数据传递和交互。

    MutationObserver

    MutationObserver是一个用于监听DOM树变化的API,它可以观察DOM节点的属性、子节点等的变化,并在变化发生时触发回调函数。

    MutationObserver的作用和价值在于:

  • 监听DOM变化:MutationObserver可以帮助我们实时监听DOM树的变化,包括节点的添加、删除、属性的修改等。这对于需要实时响应DOM变化的场景非常有用,例如在动态加载内容、实时更新UI等情况下。
  • 避免轮询:相比于传统的轮询方式,MutationObserver可以更高效地监听DOM变化。传统的轮询方式需要不断地检查DOM状态,而MutationObserver只在DOM发生变化时才会触发回调函数,避免了不必要的性能开销。
  • 精确捕获变化:MutationObserver可以精确地捕获DOM的变化,包括细微的变化,而不仅仅是节点的添加或删除。它可以观察到属性的修改、文本内容的变化等,使我们能够更细致地处理DOM的变化。
  • MutationObserver在这个应用中用于监听子页面内容的变化。当内容发生变化时,MutationObserver会触发回调函数,并在回调函数中获取内容的高度,进行相应的处理。通过MutationObserver实时捕获子页面内容的变化,从而实现动态调整iframe高度的功能。

    写在最后的更简单的方法

    以上方法是为了去除双滚动条的办法之一,即去掉 iframe 嵌入后,页面的内滚动条,但是作为B端项目,普遍使用 antd layout 来实现后台系统,而 antd 的页头页尾的距离基本不变。若将 iframe 的高度设置为屏幕高度减去 antd 页头页尾的距离,则外部的滚动条将可以去除,同样可以实现解决两个滚动条的 bug,并且使得父项目和子项目解藕,更具稳定性和复用性。

    <iframe
      style={{
        width: '100%',
        // 240 为 antd layout 的页头及页尾整体需要的高度,需要从屏幕高度中去除,以使得iframe嵌入后,去除外部页面滚动条
        height: `${screenHeight - 240}px`,
      height="100%"
      src='xxx.url.com'
           
    粉丝