크기를 얻기 위해 Javascript를 사용하여 다른 원점 iFrame과 상호 작용할 수 없습니다. 그것을 할 수있는 유일한 방법은 사용하는 것입니다 window.postMessage
와 targetOrigin
도메인으로 설정하거나 wildchar *
iframe이 소스에서. 다른 원본 사이트의 내용을 프록시하고 사용할 수 srcdoc
있지만 이것은 핵 으로 간주 되며 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.contentWindow.document
하여 부모 창에 보낼 이벤트를 사용하여 iFrame 크기를 얻을 수 있습니다 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 모두에 대해 적절한 너비와 높이를 얻게됩니다. 여기에서 온라인으로 확인하고 여기 에서 스크린 샷을 볼 수 있습니다 .
다른 출처 iFrame 크기 핵 ( 권장되지 않음 )
여기에 설명 된 방법은 해킹 이므로 절대적으로 필요하고 다른 방법이없는 경우 사용해야합니다. 대부분의 동적 생성 페이지 및 SPA 에서는 작동하지 않습니다 . 이 메소드 cors-anywhere
는https://cors-anywhere.herokuapp.com
CORS 정책을 우회하기 위해 프록시를 사용하여 페이지 HTML 소스 코드를 페치합니다 ( 간단한 CORS 프록시 서버를 작성하는 쉬운 방법이며 온라인 데모가 있습니다 ). 그러면 해당 HTML에 JS 코드를 삽입 postMessage
하여 크기를 전송합니다. 부모 문서로 iFrame. 심지어 iFrame resize
( iFrame 과 결합width: 100%
) 이벤트를 처리 하고 iFrame 크기를 부모에게 다시 게시합니다.
patchIframeHtml
:
iFrame HTML 코드를 패치하고 postMessage
iFrame 크기를 부모에게 계속 전송하는 데 사용할 사용자 정의 Javascript를 삽입하는 기능 load
입니다 resize
. origin
매개 변수에 대한 값이있는 경우 HTML <base/>
요소가 해당 오리진 URL을 사용하여 헤드 앞에 추가되므로 /some/resource/file.ext
iFrame 내의 오리진 URL 에서 HTML URI와 같은 HTML을 올바르게 가져옵니다.
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
param이 설정된 경우 프록시를 사용하여 CORS를 무시하고 페이지 HTML을 가져 오는 기능 입니다. 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"와 정확히 동일 합니다.
이제 사용자 정의 JS 코드를 삽입하여 iFrame 내에 교차 도메인을로드 할 수 있습니다.
<!-- 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의 내용을 전체 높이 로 조정할 수 있습니다 (resize에서 스크롤 막대가 깜박이지 않아야 함overflow-y: hidden
).
여기에서 온라인으로 확인할 수 있습니다 .
다시 말하지만 이것은 해킹 이므로 피해야합니다 . 우리는 할 수 없습니다 액세스 크로스 원산지 iframe이 문서 나 물건의 종류를 주입.