Boyutunu elde etmek için Javascript kullanarak farklı bir orijinli iFrame ile etkileşim kurmak mümkün değildir; Bunu yapmanın tek yolu kullanmaktır window.postMessage
ile targetOrigin
etki alanınıza seti veya wildchar *
iFrame kaynaktan. Farklı kaynak sitelerin içeriğini ve kullanımını proxy yapabilirsiniz srcdoc
, ancak bu bir hack olarak kabul edilir ve SPA'lar ve daha birçok dinamik sayfa ile çalışmaz.
Aynı başlangıç iFrame boyutu
Varsayalım ki, aynı yüksekliğe ve sabit genişliğe sahip iki aynı kökenli iFramesimiz var:
<!-- 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>
ve uzun yükseklik 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
Olayı kullanarak iframe.contentWindow.document
ana pencereye göndereceğimizi kullanarak iFrame boyutunu alabiliriz 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>
Her iki iFrame için de uygun genişlik ve yükseklik elde edeceğiz; buradan çevrimiçi kontrol edebilir ve burada ekran görüntüsünü görebilirsiniz .
Farklı kökenli iFrame boyutu kesmek ( önerilmez )
Burada açıklanan yöntem bir hack'tir ve kesinlikle gerekliyse ve başka bir yol yoksa kullanılmalıdır; dinamik olarak oluşturulan sayfaların ve SPA'ların çoğunda çalışmaz . Yöntem, sayfa HTML kaynak kodunu CORS politikasını atlamak için bir proxy kullanarak getirir ( cors-anywhere
basit bir CORS proxy sunucusu oluşturmanın kolay bir yoludur ve çevrimiçi bir demosu vardırhttps://cors-anywhere.herokuapp.com
), daha sonra kullanmak postMessage
ve boyutunu göndermek için bu HTML'ye JS kodu enjekte eder . Üst belgeye iFrame. Hatta iFrame resize
( iFrame ile birliktewidth: 100%
) olayını işler ve iFrame boyutunu üst öğeye geri gönderir.
patchIframeHtml
:
İFrame HTML kodunu yamalamak ve postMessage
iFrame boyutunu üste load
ve açık olarak göndermek için kullanılacak özel Javascript enjekte etmek için bir işlev resize
. origin
Parametre için bir değer varsa, <base/>
o başlangıç URL'sini kullanarak başlığa bir HTML öğesi eklenecektir, bu nedenle, gibi HTML URI'leri /some/resource/file.ext
iFrame içindeki başlangıç URL'si tarafından düzgün bir şekilde getirilecektir.
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 ayarlanmışsa, bir proxy kullanarak CORS'leri atlayarak sayfa HTML'si alma işlevi . postMessage
Boyut verileri gönderilirken iletilecek ek parametreler olabilir .
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();
});
}
Message event handler işlevi, "Aynı başlangıç iFrame boyutu" ile tamamen aynıdır .
Artık özel JS kodumuzu enjekte ederek bir iFrame'in içine çapraz kökenli bir alan yükleyebiliriz:
<!-- 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>
Ve iFrame'i overflow-y: auto
, iFrame gövdesi için bile kullanmadan dikey kaydırma yapmadan içeriğinin tam yüksekliğine göre boyutlandıracağız ( bu overflow-y: hidden
, yeniden boyutlandırmada kaydırma çubuğunun titrememesini sağlamalıyız ).
Online olarak buradan kontrol edebilirsiniz .
Yine bunun bir hack olduğunu ve bundan kaçınılması gerektiğini fark etmek için ; biz yapamaz erişim Çapraz Kökeni iFrame belgesi ne de şeylerin her türlü enjekte edin.