只是想分享我的解决方案和兴奋。我花了整整四天的时间进行深入研究并失败了,但我认为我已经找到了一种使 iframe 完全响应式的巧妙方法!耶!
我尝试了很多不同的方法...我不想使用双向通信隧道postMessage
因为这对于同源来说很尴尬,而对于跨源来说则很复杂(因为没有管理员愿意打开大门并代表您实现这一点)。
我尝试过使用 MutationObservers,但仍然需要几个 EventListener(调整大小、单击等)来确保布局的每次更改都得到正确处理。 - 如果脚本切换元素的可见性怎么办?或者如果它根据需要动态预加载更多内容会怎么样? - 另一个问题是从某处获取 iframe 内容的准确高度。大多数人建议使用scrollHeight
or offsetHeight
,或使用它的组合Math.max
。问题是,在 iframe 元素更改其尺寸之前,这些值不会更新。要实现这一点,您只需重置iframe.height = 0
在抓住之前scrollHeight
,但对此还有更多警告。所以,搞砸了。
然后,我有了另一个尝试的想法requestAnimationFrame
摆脱我的事件和观察者的地狱。现在,我可以立即对每个布局更改做出反应,但我仍然没有可靠的来源来推断 iframe 的内容高度。我发现getComputedStyle
, 意外地!这是一个启示!一切都很顺利。
好吧,看看我最终从无数次尝试中提取出来的代码。
function fit() {
var iframes = document.querySelectorAll("iframe.gh-fit")
for(var id = 0; id < iframes.length; id++) {
var win = iframes[id].contentWindow
var doc = win.document
var html = doc.documentElement
var body = doc.body
var ifrm = iframes[id] // or win.frameElement
if(body) {
body.style.overflowX = "scroll" // scrollbar-jitter fix
body.style.overflowY = "hidden"
}
if(html) {
html.style.overflowX = "scroll" // scrollbar-jitter fix
html.style.overflowY = "hidden"
var style = win.getComputedStyle(html)
ifrm.width = parseInt(style.getPropertyValue("width")) // round value
ifrm.height = parseInt(style.getPropertyValue("height"))
}
}
requestAnimationFrame(fit)
}
addEventListener("load", requestAnimationFrame.bind(this, fit))
就是这样,是的! - 在你的 HTML 代码中写入<iframe src="page.html" class="gh-fit gh-fullwidth"></iframe>
. The gh-fit
是一个假的 CSS 类,用于识别 DOM 中的哪些 iframe 元素应该受到脚本的影响。这gh-fullwidth
是一个简单的 CSS 类,只有一个规则width: 100%;
.
上面的脚本自动从 DOM 中获取所有 iframe,这些 iframe 具有.gh-fit
分配的班级。然后,它获取并使用预先计算的宽度和高度样式值document.getComputedStyle(iframe)
,它总是包含该元素的像素完美大小!!!刚刚好!
请注意,此解决方案不能跨域工作(任何其他解决方案也不能跨域,没有像 IFrameResizer 这样的双向通信策略)。如果 iframe 不属于你,JS 根本无法访问它的 DOM。
我能想到的唯一的其他跨域解决方案是使用像https://github.com/gnuns/allorigins https://github.com/gnuns/allorigins。但这将涉及深度复制您发出的每个请求 - 换句话说 - 您“窃取”整个页面源代码(使其成为您的并让 JS 访问 DOM)并修补此源中的每个链接/路径,以便它也通过代理。重新连接例程是一项艰巨的任务,但也是可行的。
我可能会尝试解决这个跨域问题,但那是另一天的事了。享受代码! :)