ไม่สามารถโต้ตอบกับ iFrame กำเนิดอื่นโดยใช้ Javascript เพื่อให้ได้ขนาด วิธีเดียวที่จะทำได้คือใช้window.postMessage
กับtargetOrigin
ชุดโดเมนของคุณหรือ wildchar *
จากแหล่ง iFrame คุณสามารถพร็อกซีเนื้อหาของไซต์ต้นทางและการใช้งานต่างsrcdoc
ๆ แต่ถือว่าเป็นการแฮกและมันจะไม่ทำงานกับ SPA และหน้าเว็บแบบไดนามิกอื่น ๆ อีกมากมาย
ขนาด iFrame กำเนิดเดียวกัน
สมมติว่าเรามี iFrames ต้นกำเนิดเดียวกันสองหนึ่งในความสูงสั้นและความกว้างคงที่:
<!-- 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>
เราสามารถรับขนาด iFrame ในload
เหตุการณ์โดยใช้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>
เราจะได้ความกว้างและความสูงที่เหมาะสมสำหรับทั้ง iFrames คุณสามารถตรวจสอบออนไลน์ได้ที่นี่และดูภาพที่นี่
การแฮ็กขนาด iFrame ต้นกำเนิดที่แตกต่างกัน( ไม่แนะนำให้ใช้ )
วิธีที่อธิบายไว้ที่นี่คือแฮ็คและควรใช้ถ้าจำเป็นจริงๆและไม่มีวิธีอื่น มันจะไม่ทำงานสำหรับหน้าและสปาที่สร้างขึ้นแบบไดนามิกส่วนใหญ่ วิธีการดึงหน้าซอร์สโค้ด HTML โดยใช้พร็อกซีเพื่อหลีกเลี่ยงนโยบาย CORS ( cors-anywhere
เป็นวิธีที่ง่ายในการสร้างพร็อกซีเซิร์ฟเวอร์ CORS อย่างง่ายและมีการสาธิตออนไลน์https://cors-anywhere.herokuapp.com
) จากนั้นจะอัดรหัส JS ไปยัง HTML นั้นเพื่อใช้postMessage
และส่งขนาด iFrame ไปที่เอกสารพาเรนต์ มันยังจัดการกับเหตุการณ์iFrame resize
( รวมกับ iFramewidth: 100%
) และโพสต์ขนาด iFrame กลับไปที่ผู้ปกครอง
patchIframeHtml
:
ฟังก์ชั่นการแก้ไขรหัส iFrame HTML และกำหนดเองฉีดจาวาสคริปต์ที่จะใช้postMessage
ในการส่งขนาด iFrame เพื่อแม่บนและload
resize
หากมีค่าสำหรับorigin
พารามิเตอร์<base/>
องค์ประกอบHTML จะถูกนำไปใช้กับส่วนหัวโดยใช้ URL ต้นทางดังนั้น HTML URIs เช่น/some/resource/file.ext
นั้นจะถูกดึงข้อมูลอย่างถูกต้องโดย URL ต้นทางภายใน iFrame
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
:
ฟังก์ชั่นที่จะได้รับเพจ HTML บายพาส CORS โดยใช้พร็อกซีหากuseProxy
มีการตั้งค่าพารามิเตอร์ สามารถมีพารามิเตอร์เพิ่มเติมที่จะถูกส่งไปยัง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();
});
}
ฟังก์ชั่นเหตุการณ์จัดการข้อความตรงเช่นเดียวกับใน"ต้นกำเนิดเดียวกันขนาด iFrame"
ขณะนี้เราสามารถโหลดโดเมน cross origin ภายใน iFrame ด้วยการฉีดรหัส 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>
และเราจะทำให้ iFrame มีขนาดเท่ากับเนื้อหาเต็มความสูงโดยไม่มีการเลื่อนแนวตั้งแม้ใช้overflow-y: auto
สำหรับเนื้อหาของ iFrame ( ควรเป็นoverflow-y: hidden
เช่นนั้นดังนั้นเราจึงไม่ได้รับการเลื่อนแถบเลื่อนเมื่อปรับขนาด )
คุณสามารถตรวจสอบออนไลน์ได้ที่นี่
อีกครั้งเพื่อแจ้งให้ทราบว่านี้คือการสับและมันควรจะหลีกเลี่ยง ; เราไม่สามารถเข้าถึงเอกสารCross-Origin iFrame หรือฉีดสิ่งใด ๆ