在项目中使用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>
备注:
// 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); } }
浙公网安备 33010602011771号