gpt4 book ai didi

javascript - 如何在没有纵横比假设的情况下使 iframe 响应?

转载 作者:行者123 更新时间:2023-12-01 14:45:00 25 4
gpt4 key购买 nike

如何在不假设纵横比的情况下使 iframe 响应?例如,内容可能具有任何宽度或高度,这在渲染之前是未知的。

请注意,您可以使用 Javascript。

例子:

<div id="iframe-container">
<iframe/>
</div>

尺码 iframe-container所以它的内容几乎不能在没有额外空间的情况下放在里面,换句话说,有足够的空间容纳内容,所以它可以在不滚动的情况下显示,但没有多余的空间。 Container 完美地包裹了 iframe。

This展示了如何使 iframe 响应,假设内容的纵横比为 16:9。但是在这个问题中,纵横比是可变的。

最佳答案

无法使用 Javascript 与不同来源的 iFrame 进行交互以获取它的大小;唯一的方法是使用 window.postMessage targetOrigin设置为您的域或通配符 *来自 iFrame 源。可以代理不同源站的内容,使用srcdoc ,但这被认为是一种 hack,它不适用于 SPA 和许多其他更动态的页面。

同源 iFrame 大小

假设我们有两个相同的原点 iFrame,一个是短高度,一个是固定宽度:

<!-- iframe-short.html -->
<head>
<style type="text/css">
html, body { margin: 0 }
body {
width: 300px;
}
</style>
</head>
<body>
<div>This is an iFrame</div>
<span id="val">(val)</span>
</body>

和一个长高的 iFrame:

<!-- iframe-long.html -->
<head>
<style type="text/css">
html, body { margin: 0 }
#expander {
height: 1200px;
}
</style>
</head>
<body>
<div>This is a long height iFrame Start</div>
<span id="val">(val)</span>
<div id="expander"></div>
<div>This is a long height iFrame End</div>
<span id="val">(val)</span>
</body>

我们可以在 load 上获取 iFrame 大小事件使用 iframe.contentWindow.document我们将使用 postMessage 发送到父窗口:

<div>
<iframe id="iframe-local" src="iframe-short.html"></iframe>
</div>
<div>
<iframe id="iframe-long" src="iframe-long.html"></iframe>
</div>

<script>

function iframeLoad() {
window.top.postMessage({
iframeWidth: this.contentWindow.document.body.scrollWidth,
iframeHeight: this.contentWindow.document.body.scrollHeight,
params: {
id: this.getAttribute('id')
}
});
}

window.addEventListener('message', ({
data: {
iframeWidth,
iframeHeight,
params: {
id
} = {}
}
}) => {
// We add 6 pixels because we have "border-width: 3px" for all the iframes

if (iframeWidth) {
document.getElementById(id).style.width = `${iframeWidth + 6}px`;
}

if (iframeHeight) {
document.getElementById(id).style.height = `${iframeHeight + 6}px`;
}

}, false);

document.getElementById('iframe-local').addEventListener('load', iframeLoad);
document.getElementById('iframe-long').addEventListener('load', iframeLoad);

</script>

我们将为两个 iFrame 获得适当的宽度和高度;可以在线查看 here并查看屏幕截图 here .

不同来源的 iFrame 大小破解(不推荐)

此处描述的方法是一种 hack,如果绝对必要并且没有其他方法,则应该使用它; 不行对于大多数动态生成的页面和 SPA。该方法使用代理获取页面 HTML 源代码以绕过 CORS 策略( cors-anywhere 是创建简单 CORS 代理服务器的简单方法,它有一个在线演示 https://cors-anywhere.herokuapp.com)然后将 JS 代码注入(inject)该 HTML 以使用 postMessage并将 iFrame 的大小发送到父文档。它甚至可以处理 iFrame resize (结合 iFrame width: 100% )事件并将 iFrame 大小发送回父级。
patchIframeHtml :

修补 iFrame HTML 代码并注入(inject)将使用 postMessage 的自定义 Javascript 的函数将 iFrame 大小发送到 load 上的父级和 resize .如果有 origin 的值参数,然后是 HTML <base/>元素将使用该原始 URL 附加到头部,因此,HTML URI 像 /some/resource/file.ext将通过 iFrame 内的原始 URL 正确获取。

function patchIframeHtml(html, origin, params = {}) {
// Create a DOM parser
const parser = new DOMParser();

// Create a document parsing the HTML as "text/html"
const doc = parser.parseFromString(html, 'text/html');

// Create the script element that will be injected to the iFrame
const script = doc.createElement('script');

// Set the script code
script.textContent = `
window.addEventListener('load', () => {
// Set iFrame document "height: auto" and "overlow-y: auto",
// so to get auto height. We set "overlow-y: auto" for demontration
// and in usage it should be "overlow-y: hidden"
document.body.style.height = 'auto';
document.body.style.overflowY = 'auto';

poseResizeMessage();
});

window.addEventListener('resize', poseResizeMessage);

function poseResizeMessage() {
window.top.postMessage({
// iframeWidth: document.body.scrollWidth,
iframeHeight: document.body.scrollHeight,
// pass the params as encoded URI JSON string
// and decode them back inside iFrame
params: JSON.parse(decodeURIComponent('${encodeURIComponent(JSON.stringify(params))}'))
}, '*');
}
`;

// Append the custom script element to the iFrame body
doc.body.appendChild(script);

// If we have an origin URL,
// create a base tag using that origin
// and prepend it to the head
if (origin) {
const base = doc.createElement('base');
base.setAttribute('href', origin);

doc.head.prepend(base);
}

// Return the document altered HTML that contains the injected script
return doc.documentElement.outerHTML;
}
getIframeHtml :

如果 useProxy 使用代理获取页面 HTML 绕过 CORS 的函数参数已设置。可以有其他参数将传递给 postMessage发送尺寸数据时。

function getIframeHtml(url, useProxy = false, params = {}) {
return new Promise(resolve => {
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
// If we use a proxy,
// set the origin so it will be placed on a base tag inside iFrame head
let origin = useProxy && (new URL(url)).origin;

const patchedHtml = patchIframeHtml(xhr.responseText, origin, params);
resolve(patchedHtml);
}
}

// Use cors-anywhere proxy if useProxy is set
xhr.open('GET', useProxy ? `https://cors-anywhere.herokuapp.com/${url}` : url, true);
xhr.send();
});
}

消息事件处理函数与“Same origin iFrame size”中的完全相同。

我们现在可以在 iFrame 中加载一个跨域域,并注入(inject)我们的自定义 JS 代码:

<!-- It's important that the iFrame must have a 100% width 
for the resize event to work -->
<iframe id="iframe-cross" style="width: 100%"></iframe>

<script>
window.addEventListener('DOMContentLoaded', async () => {
const crossDomainHtml = await getIframeHtml(
'https://en.wikipedia.org/wiki/HTML', true /* useProxy */, { id: 'iframe-cross' }
);

// We use srcdoc attribute to set the iFrame HTML instead of a src URL
document.getElementById('iframe-cross').setAttribute('srcdoc', crossDomainHtml);
});
</script>

即使使用 overflow-y: auto,我们也会将 iFrame 调整到其内容的全高,而无需任何垂直滚动。对于 iFrame 主体(它应该是 overflow-y: hidden,所以我们不会在调整大小时滚动条闪烁)。

您可以在线查看 here .

再次注意到 这是一个黑客 应该避免 ;我们 不能访问 Cross-Origin iFrame 文档,也不注入(inject)任何东西。

关于javascript - 如何在没有纵横比假设的情况下使 iframe 响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61407418/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com