我想分享我的解决方案和兴奋心情。我经过四整天的密集研究和失败,但我认为我已经找到了一种使iframes完全响应的巧妙方式!耶!
我尝试了很多不同的方法... 我不想使用双向通信隧道,如postMessage,因为对于同源来说很尴尬,对于跨源来说则很复杂(因为没有管理员想要打开门并代表你实现这个功能)。
我试过使用MutationObservers,仍然需要几个EventListeners(resize、click等)来确保每次布局变化都能得到正确处理。-如果一个脚本切换元素的可见性会怎样?或者它动态地按需预加载更多内容呢?-另一个问题是从某个地方获取iframe内容的准确高度。大多数人建议使用scrollHeight或offsetHeight,或者通过使用Math.max的组合来获取它。问题是,这些值直到iframe元素更改其尺寸才会更新。要实现这一点,您可以简单地在抓取scrollHeight之前重置iframe.height = 0,但这还有更多的注意事项。所以,放弃掉这个。
然后,我又有了另一个实验想法,用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]
if(body) {
body.style.overflowX = "scroll"
body.style.overflowY = "hidden"
}
if(html) {
html.style.overflowX = "scroll"
html.style.overflowY = "hidden"
var style = win.getComputedStyle(html)
ifrm.width = parseInt(style.getPropertyValue("width"))
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>
。其中
gh-fit
只是一个虚假的CSS类,用于标识DOM中哪些iframe元素应受脚本影响。而
gh-fullwidth
是一个简单的CSS类,只包含一条规则
width: 100%;
。
上面的脚本会自动获取DOM中所有带有已分配
.gh-fit
类的iframe。然后从
document.getComputedStyle(iframe)
中获取预先计算好的宽度和高度的样式值,该方法总是返回该元素的像素完美大小!完美无缺!
注意,此解决方案不适用于跨源(没有任何其他解决方案可以在没有IFrameResizer等双向通信策略的情况下访问iframe DOM)。如果iframe不属于你,JavaScript无法访问它的DOM。
我能想到的仅有的其他跨源解决方案是使用代理,例如
https://github.com/gnuns/allorigins。但这将涉及每次请求的深复制 - 换句话说 - 你“窃取”整个页面源代码(使其成为你的并让JavaScript访问DOM)并修补该源中的每个链接/路径,以便它也经过代理。重新链接程序很困难,但可行。
我可能会尝试解决这个跨源问题,但那是另一天的事情了。享受代码吧! :)