在项目中使用iframe内嵌同源第三方页面,获取到页面高度,将获取到的高度给iframe设置成功后,避免页面出现两个滚动条。

<template>
    <!-- ref 用于获取 iframe 实例,src 为同域页面地址 -->
    <iframe 
    ref="iframeRef"
    :src="url" 
    frameborder="0" 
    width="100%" 
    scrolling="no"
    height="1600px"
    @load="setIframeHeight"
    ></iframe>
</template>
<script>
export default {
  data() {
    return {
      url: 'http://10.88/lc/199792321',
      urlLarge: 'http://10.88/lc/199649321',
      urlMiddle: 'http://10.88/lc/1996436321',
      heightTimer: null,
      readyTimer: null,
      devicePixelRatio: window.devicePixelRatio || 1,// 设备像素比(默认 1)
    }
  },  
  mounted() {
    // 计算实际物理分辨率(CSS 像素 × DPR)
    const realWidth = window.screen.width * this.devicePixelRatio;
    const realHeight = window.screen.height * this.devicePixelRatio;
    // 判断屏幕实际物理分辨率是否大于 1600px
    if (realWidth > 1800) {
      this.url = this.urlLarge;
    } else {
      this.url = this.urlMiddle;
    }
  },
  methods: {
    handleIframeLoad() {
      // console.log('iframe 基础加载完成(DOM+静态资源)');
      // load 触发后启动检测
      this.setIframeHeight();
    },
    // 初始化/更新 iframe 高度 load函数基础加载完成(DOM+静态资源加载完成)
    setIframeHeight() {
      // console.log('iframe 基础加载完成(DOM+静态资源)');
      const iframe = this.$refs.iframeRef;
      // alert(1)
      if (!iframe || !iframe.contentDocument) return 0;
      // 延迟 300ms 计算(适配子页面异步内容渲染)
      // 监听子页面 document 状态
      const checkReadyState = () => {
        const readyState = iframe.contentDocument.readyState;
        if (readyState === 'complete' && iframe.contentDocument.getElementById('wrapper')) {
          console.log('iframe 子页面 DOM 完全解析完成');
          // this.isIframeLoaded = true;
          setTimeout(() => {
            // 2. 获取当前浏览器缩放比例(关键!)
            const zoomRatio = window.devicePixelRatio || 1;
            const offsetHeight = iframe.contentDocument.getElementById('wrapper').offsetHeight;
            this.$refs.iframeRef.style.height = (offsetHeight + 18)/zoomRatio + 'px';
          }, 300);
          // 清除定时器
          clearInterval(this.readyTimer);
        }
      }
      // 初始化检测
      checkReadyState();
      // 定时检测(避免初始状态未完成)
      this.readyTimer = setInterval(checkReadyState, 100);

      // // 监听子页面 resize(动态内容变化时重新计算)
      // this.$refs.iframeRef.contentWindow.addEventListener('resize', () => {
      //   const height = this.getIframeExactHeight();
      //   this.$refs.iframeRef.style.height = `${height}px`;
      // });
    },
    // Vue 组件中封装精准获取高度的方法
    getIframeExactHeight() {
      const iframe = this.$refs.iframeRef;
      if (!iframe || !iframe.contentDocument) return 0;

      const doc = iframe.contentDocument;
      const win = iframe.contentWindow;

      console.log(iframe);
      console.log(iframe.contentDocument.getElementById('wrapper').offsetHeight);
      console.log('doc.body.scrollHeight', doc.body.scrollHeight);
      console.log('doc.documentElement.scrollHeight', doc.documentElement.scrollHeight);
      console.log('doc.body.offsetHeight', doc.body.offsetHeight);
      console.log('doc.documentElement.offsetHeight', doc.documentElement.offsetHeight);
      console.log('win.innerHeight', win.innerHeight);
      // 全维度计算子页面实际高度(覆盖滚动/偏移/可视高度)
      const height = Math.max(
        doc.body.scrollHeight,    // 内容滚动高度(核心)
        doc.documentElement.scrollHeight, // html 节点滚动高度
        doc.body.offsetHeight,    // 内容偏移高度(含 padding/border)
        doc.documentElement.offsetHeight, // html 节点偏移高度
        win.innerHeight           // 子页面可视高度(兜底)
      );

      // console.log('iframe内容高度:', height);
      // 叠加冗余高度(根据实际调整,建议 20~50px,覆盖子页面 margin/padding)
      return height + 30; 
    },
    // iframe 加载完成后初始化高度
    handleIframeLoad() {
      this.setIframeHeight();
      // 监听 iframe 内部窗口大小变化(如子页面有动态内容)
      const iframeWindow = this.$refs.iframeRef.contentWindow;
      iframeWindow.addEventListener('resize', this.setIframeHeight);
    }
  },  
  beforeDestroy() {
    // 销毁监听,避免内存泄漏
    // if (this.$refs.iframeRef) {
    //   const iframeWindow = this.$refs.iframeRef.contentWindow;
    //   iframeWindow.removeEventListener('resize', this.setIframeHeight);
    // }

    // clearInterval(this.heightTimer); // 销毁定时器
      // 销毁定时器
    if (this.readyTimer) clearInterval(this.readyTimer);
  }
}
</script>

<style>

</style>
View Code

备注:

// iframe 的@load="setIframeHeight" 函数代表基础加载完成(DOM+静态资源)
// iframe.contentDocument.readyState== 'complete'代表iframe 子页面 DOM 完全解析完成
//页面缩放后「显示高度(1304px)与实际高度(1007px)不一致」,核心原因是 “缩放会改变 CSS 像素与物理像素的映射关系”,再叠加「浏览器 / 系统缩放规则、DOM 高度计算口径差异」导致的视觉与实际值偏差。
// 最后获取高度根据自己实际项目获取(我这里获取的内嵌页面wraper内容高度)后再设置iframe的高度。
    // 初始化/更新 iframe 高度 load函数基础加载完成(DOM+静态资源加载完成)
    setIframeHeight() {
      // console.log('iframe 基础加载完成(DOM+静态资源)');
      const iframe = this.$refs.iframeRef;
      // alert(1)
      if (!iframe || !iframe.contentDocument) return 0;
      // 延迟 300ms 计算(适配子页面异步内容渲染)
      // 监听子页面 document 状态
      const checkReadyState = () => {
        const readyState = iframe.contentDocument.readyState;
        if (readyState === 'complete' && iframe.contentDocument.getElementById('wrapper')) {
          console.log('iframe 子页面 DOM 完全解析完成');
          // this.isIframeLoaded = true;
          setTimeout(() => {
            // 2. 获取当前浏览器缩放比例(关键!)
            const zoomRatio = window.devicePixelRatio || 1;
             const offsetHeight = iframe.contentDocument.getElementById('wrapper').offsetHeight;// 子页面内容高度
              const offsetWidth = iframe.contentDocument.getElementById('wrapper').offsetWidth;// 子页面内容宽度
              const iframeWarpWidth = document.getElementById('iframeWarp').offsetWidth*zoomRatio;// 父元素宽度
              const scale = iframeWarpWidth/offsetWidth;// 父元素宽度/子页面内容宽度 = 缩放比例
              this.$refs.iframeRef.style.height = (offsetHeight*scale + 6)/zoomRatio + 'px';
          }, 300);
          // 清除定时器
          clearInterval(this.readyTimer);
        }
      }

 

posted on 2025-12-05 09:35  刘世涛6192  阅读(9)  评论(0)    收藏  举报