Изменение размера фрейма в зависимости от содержимого
Я работаю над iGoogle-подобным приложением. Контент из других приложений (в других доменах) показывается с помощью iframes.
Как изменить размеры фреймов, чтобы они соответствовали высоте содержимого фреймов?
Я пытался расшифровать javascript, который использует Google, но он запутан, и поиск в Интернете до сих пор был бесплодным.
Обновление: обратите внимание, что контент загружается из других доменов, поэтому применяется та же политика происхождения.
26 ответов
У нас была такая проблема, но немного обратная вашей ситуации - мы предоставляли контент iframed сайтам в других доменах, поэтому такая же политика происхождения также была проблемой. После многих часов, проведенных в поисках Google, мы в конечном итоге нашли (несколько..) работоспособное решение, которое вы можете адаптировать к вашим потребностям.
Существует способ обойти одну и ту же политику происхождения, но она требует изменений как для содержимого iframed, так и для страницы создания кадров, поэтому, если у вас нет возможности запрашивать изменения с обеих сторон, этот метод не будет очень полезен для вас, Боюсь.
Существует особенность браузера, которая позволяет нам обходить ту же политику происхождения - javascript может взаимодействовать либо со страницами в своем собственном домене, либо со страницами, на которые он встроен, но не со страницами, на которых он создан, например, если у вас есть:
www.foo.com/home.html, which iframes
|-> www.bar.net/framed.html, which iframes
|-> www.foo.com/helper.html
затем home.html
может общаться с framed.html
(iframed) и helper.html
(тот же домен).
Communication options for each page:
+-------------------------+-----------+-------------+-------------+
| | home.html | framed.html | helper.html |
+-------------------------+-----------+-------------+-------------+
| www.foo.com/home.html | N/A | YES | YES |
| www.bar.net/framed.html | NO | N/A | YES |
| www.foo.com/helper.html | YES | YES | N/A |
+-------------------------+-----------+-------------+-------------+
framed.html
может отправлять сообщения helper.html
(iframed) но не home.html
(ребенок не может общаться между доменами с родителем).
Ключевым моментом здесь является то, что helper.html
может получать сообщения от framed.html
и может также общаться с home.html
,
Так по сути, когда framed.html
грузит, вырабатывает собственную высоту, рассказывает helper.html
, который передает сообщение на home.html
который может затем изменить размер фрейма, в котором framed.html
сидит.
Самый простой способ передачи сообщений от framed.html
в helper.html
был через аргумент URL. Сделать это, framed.html
имеет iframe с src=''
указано. Когда это onload
срабатывает, он оценивает свою собственную высоту и устанавливает в этом месте src для iframe helper.html?height=N
Здесь есть объяснение того, как Facebook справляется с этим, что может быть немного яснее, чем мое выше!
Код
В www.foo.com/home.html
требуется следующий код javascript (его можно загрузить из файла.js в любом домене, между прочим..):
<script>
// Resize iframe to full height
function resizeIframe(height)
{
// "+60" is a general rule of thumb to allow for differences in
// IE & and FF height reporting, can be adjusted as required..
document.getElementById('frame_name_here').height = parseInt(height)+60;
}
</script>
<iframe id='frame_name_here' src='http://www.bar.net/framed.html'></iframe>
В www.bar.net/framed.html
:
<body onload="iframeResizePipe()">
<iframe id="helpframe" src='' height='0' width='0' frameborder='0'></iframe>
<script type="text/javascript">
function iframeResizePipe()
{
// What's the page height?
var height = document.body.scrollHeight;
// Going to 'pipe' the data to the parent through the helpframe..
var pipe = document.getElementById('helpframe');
// Cachebuster a precaution here to stop browser caching interfering
pipe.src = 'http://www.foo.com/helper.html?height='+height+'&cacheb='+Math.random();
}
</script>
Содержание www.foo.com/helper.html
:
<html>
<!--
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content
-->
<body onload="parentIframeResize()">
<script>
// Tell the parent iframe what height the iframe needs to be
function parentIframeResize()
{
var height = getParam('height');
// This works as our parent's parent is on our domain..
parent.parent.resizeIframe(height);
}
// Helper function, parse param from request string
function getParam( name )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
</script>
</body>
</html>
Если вам не нужно обрабатывать контент iframe из другого домена, попробуйте этот код, он полностью решит проблему и прост:
<script language="JavaScript">
<!--
function autoResize(id){
var newheight;
var newwidth;
if(document.getElementById){
newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
}
document.getElementById(id).height= (newheight) + "px";
document.getElementById(id).width= (newwidth) + "px";
}
//-->
</script>
<iframe src="usagelogs/default.aspx" width="100%" height="200px" id="iframe1" marginheight="0" frameborder="0" onLoad="autoResize('iframe1');"></iframe>
https://developer.mozilla.org/en/DOM/window.postMessage
window.postMessage ()
window.postMessage - это метод безопасного включения связи между источниками. Как правило, сценарии на разных страницах могут получать доступ друг к другу только тогда и только тогда, когда страницы, которые их выполнили, находятся в местах с одинаковым протоколом (обычно с http), номером порта (по умолчанию для http используется 80) и хостом (по модулю). document.domain устанавливается обеими страницами на одно и то же значение). window.postMessage предоставляет управляемый механизм, позволяющий обойти это ограничение безопасным способом при правильном использовании.
Резюме
window.postMessage, когда вызывается, вызывает отправку MessageEvent в целевом окне, когда завершается любой ожидающий сценарий, который должен быть выполнен (например, оставшиеся обработчики событий, если window.postMessage вызывается из обработчика событий, предварительно установленные ожидания ожидания и т. д.). MessageEvent имеет тип сообщения, свойство data, для которого задано строковое значение первого аргумента, предоставленного window.postMessage, свойство origin, соответствующее источнику основного документа в окне, вызывающем window.postMessage во временном окне. Был вызван postMessage и свойство источника, которое является окном, из которого вызывается window.postMessage. (Другие стандартные свойства событий присутствуют с их ожидаемыми значениями.)
Библиотека iFrame-Resizer использует postMessage для сохранения размера iFrame для своего контента, а также MutationObserver для обнаружения изменений в контенте и не зависит от jQuery.
https://github.com/davidjbradshaw/iframe-resizer
jQuery: совершенство междоменных сценариев
http://benalman.com/projects/jquery-postmessage-plugin/
Есть демонстрация изменения размера окна iframe...
http://benalman.com/code/projects/jquery-postmessage/examples/iframe/
В этой статье показано, как удалить зависимость от jQuery... Plus содержит много полезной информации и ссылок на другие решения.
http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/
Пример Barebones...
http://onlineaspect.com/uploads/postmessage/parent.html
HTML 5 рабочий проект для window.postMessage
http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html
Джон Резиг об обмене сообщениями между окнами
Простейший способ использования jQuery:
$("iframe")
.attr({"scrolling": "no", "src":"http://www.someotherlink.com/"})
.load(function() {
$(this).css("height", $(this).contents().height() + "px");
});
Наконец, я нашел другое решение для отправки данных на родительский сайт из iframe, используя window.postMessage(message, targetOrigin);
, Здесь я объясняю, как я это сделал.
Сайт A = http://foo.com/ Сайт B = http://bar.com/
Сайт B загружается внутри сайта. Сайт
Сайт Site B имеет эту строку
window.parent.postMessage("Hello From IFrame", "*");
или же
window.parent.postMessage("Hello From IFrame", "http://foo.com");
Тогда сайт А имеет следующий код
// Here "addEventListener" is for standards-compliant web browsers and "attachEvent" is for IE Browsers.
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen to message from child IFrame window
eventer(messageEvent, function (e) {
alert(e.data);
// Do whatever you want to do with the data got from IFrame in Parent form.
}, false);
Если вы хотите добавить безопасное соединение, вы можете использовать это, если условие в eventer(messageEvent, function (e) {})
if (e.origin == 'http://iframe.example.com') {
alert(e.data);
// Do whatever you want to do with the data got from IFrame in Parent form.
}
Для IE
Внутри IFrame:
window.parent.postMessage('{"key":"value"}','*');
За пределами:
eventer(messageEvent, function (e) {
var data = jQuery.parseJSON(e.data);
doSomething(data.key);
}, false);
Решение на http://www.phinesolutions.com/use-jquery-to-adjust-the-iframe-height.html прекрасно работает (использует jQuery):
<script type=”text/javascript”>
$(document).ready(function() {
var theFrame = $(”#iFrameToAdjust”, parent.document.body);
theFrame.height($(document.body).height() + 30);
});
</script>
Я не знаю, что вам нужно добавить 30 к длине... 1 работал для меня.
К вашему сведению: если у вас уже есть атрибут height в вашем iFrame, это просто добавляет style="height: xxx". Это может быть не то, что вы хотите.
Может быть немного поздно, так как все остальные ответы старше:-) но... вот мое решение. Проверено в реальных FF, Chrome и Safari 5.0.
CSS:
iframe {border:0; overflow:hidden;}
JavaScript:
$(document).ready(function(){
$("iframe").load( function () {
var c = (this.contentWindow || this.contentDocument);
if (c.document) d = c.document;
var ih = $(d).outerHeight();
var iw = $(d).outerWidth();
$(this).css({
height: ih,
width: iw
});
});
});
Надеюсь, это кому-нибудь поможет.
Этот ответ применим только к веб-сайтам, которые используют Bootstrap. Функция адаптивного встраивания Bootstrap делает свою работу. Он основан на ширине (а не высоте) содержимого.
<!-- 16:9 aspect ratio -->
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" src="http://www.youtube.com/embed/WsFWhL4Y84Y"></iframe>
</div>
jsfiddle: http://jsfiddle.net/00qggsjj/2/
Если у вас есть контроль над содержимым iframe, я настоятельно рекомендую использовать
ResizeObserver
Просто вставьте следующее в конце
srcdoc
атрибут
iframe
,избегайте его, если это необходимо.
<script type="text/javascript">
var ro = new ResizeObserver(entries => {
for (let entry of entries) {
const cr = entry.contentRect;
// console.log(window.frameElement);
window.frameElement.style.height =cr.height +30+ "px";
}
});
ro.observe(document.body);
</script>
Вот простое решение с использованием динамически генерируемой таблицы стилей, обслуживаемой тем же сервером, что и содержимое iframe. Проще говоря, таблица стилей "знает", что находится в iframe, и знает размеры, используемые для стилизации iframe. Это обходит те же ограничения политики происхождения.
http://www.8degrees.co.nz/2010/06/09/dynamically-resize-an-iframe-depending-on-its-content/
Таким образом, поставляемый код iframe будет иметь сопровождающую таблицу стилей, например так...
<link href="http://your.site/path/to/css?contents_id=1234&dom_id=iframe_widget" rel="stylesheet" type="text/css" />
<iframe id="iframe_widget" src="http://your.site/path/to/content?content_id=1234" frameborder="0" width="100%" scrolling="no"></iframe>
Это требует, чтобы логика на стороне сервера была способна вычислять размеры визуализированного содержимого iframe.
<html>
<head>
<script>
function frameSize(id){
var frameHeight;
document.getElementById(id).height=0 + "px";
if(document.getElementById){
newheight=document.getElementById(id).contentWindow.document.body.scrollHeight;
}
document.getElementById(id).height= (frameHeight) + "px";
}
</script>
</head>
<body>
<iframe id="frame" src="startframe.html" frameborder="0" marginheight="0" hspace=20 width="100%"
onload="javascript:frameSize('frame');">
<p>This will work, but you need to host it on an http server, you can do it locally. </p>
</body>
</html>
Я внедряю решение ConroyP для фреймов в кадре, чтобы заменить решение, основанное на настройке document.domain, но оказалось, что довольно сложно правильно определить высоту содержимого iframe в разных браузерах (тестирование с FF11, Ch17 и IE9 сейчас).
ConroyP использует:
var height = document.body.scrollHeight;
Но это работает только при начальной загрузке страницы. Мой iframe имеет динамическое содержимое, и мне нужно изменить размер iframe для определенных событий.
В итоге я использовал разные свойства JS для разных браузеров.
function getDim () {
var body = document.body,
html = document.documentElement;
var bc = body.clientHeight;
var bo = body.offsetHeight;
var bs = body.scrollHeight;
var hc = html.clientHeight;
var ho = html.offsetHeight;
var hs = html.scrollHeight;
var h = Math.max(bc, bo, bs, hc, hs, ho);
var bd = getBrowserData();
// Select height property to use depending on browser
if (bd.isGecko) {
// FF 11
h = hc;
} else if (bd.isChrome) {
// CH 17
h = hc;
} else if (bd.isIE) {
// IE 9
h = bs;
}
return h;
}
getBrowserData () - это функция обнаружения браузера, "вдохновленная" http://docs.sencha.com/core/source/Ext.html функцией Ext Core.
Это хорошо работает для FF и IE, но затем возникли проблемы с Chrome. Одной из них была проблема синхронизации, по-видимому, Chrome требуется некоторое время, чтобы установить / определить высоту фрейма. Кроме того, Chrome также никогда не возвращает корректно высоту содержимого в iframe, если iframe был выше содержимого. Это не будет работать с динамическим контентом, когда высота уменьшается.
Чтобы решить эту проблему, я всегда устанавливаю значение iframe на низкую высоту, прежде чем определять высоту содержимого, а затем устанавливаю высоту iframe на правильное значение.
function resize () {
// Reset the iframes height to a low value.
// Otherwise Chrome won't detect the content height of the iframe.
setIframeHeight(150);
// Delay getting the dimensions because Chrome needs
// a few moments to get the correct height.
setTimeout("getDimAndResize()", 100);
}
Код не оптимизирован, это из моего тестирования на уровне:)
Надеюсь, кто-то найдет это полезным!
Это старая ветка, но в 2020 году это все еще актуальный вопрос. Я на самом деле опубликовал этот ответ в другом старом потоке ^^ ( /questions/34536145/kak-sdelat-iframe-100-vyisotyi-v-zavisimosti-ot-ego-soderzhaniya/56564098#56564098)
Просто хотел поделиться своим решением и волнением. Мне потребовалось целых четыре дня интенсивных исследований и неудач, но я думаю, что нашел изящный способ сделать фреймы полностью адаптивными! Ура!
Я испробовал массу разных подходов... Я не хотел использовать туннель двусторонней связи, как в
postMessage
потому что это неудобно для одинакового происхождения и сложно для перекрестного происхождения (поскольку ни один администратор не хочет открывать двери и реализовывать это от вашего имени).
Я пробовал использовать MutationObservers, и мне все еще требовалось несколько слушателей событий (изменение размера, щелчок,..), чтобы гарантировать, что каждое изменение макета обрабатывается правильно. - Что, если скрипт переключает видимость элемента? Или что, если он динамически предварительно загружает больше контента по запросу? - Другая проблема заключалась в получении откуда-то точной высоты содержимого iframe. Большинство людей предлагают использовать
scrollHeight
или же
offsetHeight
, или их комбинацию с помощью
Math.max
. Проблема в том, что эти значения не обновляются до тех пор, пока элемент iframe не изменит свои размеры. Для этого вы можете просто сбросить
iframe.height = 0
прежде чем схватить
scrollHeight
, но здесь есть еще кое-что. Итак, к черту это.
Затем у меня появилась другая идея поэкспериментировать с
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] // or win.frameElement
if(body) {
body.style.overflowX = "scroll" // scrollbar-jitter fix
body.style.overflowY = "hidden"
}
if(html) {
html.style.overflowX = "scroll" // scrollbar-jitter fix
html.style.overflowY = "hidden"
var style = win.getComputedStyle(html)
ifrm.width = parseInt(style.getPropertyValue("width")) // round value
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, используемый для определения того, на какие элементы iframe в вашей DOM должен воздействовать скрипт. В
gh-fullwidth
это простой класс CSS с одним правилом
width: 100%;
.
Приведенный выше скрипт автоматически извлекает все фреймы из DOM, у которых есть
.gh-fit
присвоенный класс. Затем он берет и использует предварительно рассчитанные значения стиля для ширины и высоты из
document.getComputedStyle(iframe)
, которые всегда содержат идеальный размер этого элемента!!! Просто отлично!
Обратите внимание: это решение не работает с разными источниками (как и любое другое решение без стратегии двусторонней связи, такой как IFrameResizer). JS просто не может получить доступ к DOM iframe, если он вам не принадлежит.
Единственное другое решение с перекрестным происхождением, которое я могу придумать, - это использовать прокси, например https://github.com/gnuns/allorigins. Но это потребует глубокого копирования каждого запроса, который вы делаете - другими словами, вы "крадете" весь исходный код страницы (чтобы сделать его своим и позволить JS получить доступ к DOM), и вы исправляете каждую ссылку / путь в этом источнике, чтобы он также проходит через прокси. Процедура повторного связывания - сложная, но выполнимая.
Я, наверное, попробую себя решить с этой проблемой перекрестного происхождения, но это в другой день. Наслаждайтесь кодом!:)
https://getbootstrap.com/docs/4.0/utilities/embed/
После долгих исследований меня осенило, что это не уникальная проблема, я уверен, что Bootstrap справится с ней. И вот…
Вот подход jQuery, который добавляет информацию в json через атрибут src iframe. Вот демонстрация, измените размер и прокрутите это окно... Полученный URL с json выглядит следующим образом... http://fiddle.jshell.net/zippyskippy/RJN3G/show/
Вот скрипта исходного кода http://jsfiddle.net/zippyskippy/RJN3G/
function updateLocation(){
var loc = window.location.href;
window.location.href = loc.replace(/#{.*}#/,"")
+ "#{docHeight:"+$(document).height()
+ ",windowHeight:"+$(window).height()
+ ",scrollHeight:"+$(window).scrollTop()
+"}#";
};
//setInterval(updateLocation,500);
$(window).resize(updateLocation);
$(window).scroll(updateLocation);
Я читал здесь много ответов, но почти каждый дал какой-то блок кадра с перекрестным происхождением.
Пример ошибки:
Uncaught DOMException: заблокировал фрейм с нулевым источником доступа к фрейму с перекрестным источником.
То же самое для ответов в связанной теме:
Я не хочу использовать стороннюю библиотеку, например
iFrame Resizer
или аналогичная библиотека.
Ответ от @ChrisJacob близок, но мне не хватает полного рабочего примера, а не только ссылок. @Selvamani и @latitov тоже хорошие дополнения.
/questions/7723796/izmenenie-razmera-frejma-v-zavisimosti-ot-soderzhimogo/7723825#7723825
я использую
width="100%"
для но код также можно изменить для работы с шириной.
Вот как я решил установить индивидуальную высоту для:
Встроенный :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description"
content="Web site" />
<title>Test with embedded iframe</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<iframe id="ifrm" src="https://localhost:44335/package/details?key=123" width="100%"></iframe>
<script type="text/javascript">
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
console.log("Got message: " + JSON.stringify(evt.data) + " from origin: " + evt.origin);
// Do we trust the sender of this message?
if (evt.origin !== "https://localhost:44335") {
return;
}
if (evt.data.type === "frame-resized") {
document.getElementById("ifrm").style.height = evt.data.value + "px";
}
}
</script>
</body>
</html>
iframe source
, пример из
Create React App
но только
HTML
а также
JS
используется.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description"
content="Web site created using create-react-app" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript">
//Don't run unless in an iframe
if (self !== top) {
var rootHeight;
setInterval(function () {
var rootElement = document.getElementById("root");
if (rootElement) {
var currentRootHeight = rootElement.offsetHeight;
//Only send values if height has changed since last time
if (rootHeight !== currentRootHeight) {
//postMessage to set iframe height
window.parent.postMessage({ "type": "frame-resized", "value": currentRootHeight }, '*');
rootHeight = currentRootHeight;
}
}
}
, 1000);
}
</script>
</body>
</html>
Код, конечно, можно изменить, но он очень хорошо работает с динамическим контентом.
setInterval
активируется только в том случае, если контент встроен в
iframe
а также
postMessage
отправляет сообщение только при изменении высоты.
Вы можете узнать больше о
Window.postMessage()
здесь, но описание очень хорошо подходит для того, чего мы хотим достичь:
Метод window.postMessage () безопасно разрешает обмен данными между объектами Window между источниками; например, между страницей и всплывающим окном, которое она породила, или между страницей и встроенным в нее iframe.
Обычно сценариям на разных страницах разрешен доступ друг к другу тогда и только тогда, когда страницы, из которых они происходят, используют один и тот же протокол, номер порта и хост (также известный как «политика одного источника»). window.postMessage () предоставляет управляемый механизм для безопасного обхода этого ограничения (при правильном использовании).
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Гаджеты iGoogle должны активно реализовывать изменение размера, поэтому я предполагаю, что в междоменной модели вы не сможете сделать это без участия удаленного контента. Если ваш контент может отправлять сообщение с новым размером на страницу контейнера с использованием типичных междоменных методов связи, то все остальное просто.
Если вы хотите уменьшить масштаб веб-страницы, чтобы она соответствовала размеру фрейма:
- Вы должны изменить размер iframe, чтобы он соответствовал содержанию
- Затем вы должны уменьшить весь iframe с загруженным содержимым веб-страницы.
Вот пример:
<div id="wrap">
<IFRAME ID="frame" name="Main" src ="http://www.google.com" />
</div>
<style type="text/css">
#wrap { width: 130px; height: 130px; padding: 0; overflow: hidden; }
#frame { width: 900px; height: 600px; border: 1px solid black; }
#frame { zoom:0.15; -moz-transform:scale(0.15);-moz-transform-origin: 0 0; }
</style>
получить высоту содержимого iframe, затем передать его этому iframe
var iframes = document.getElementsByTagName("iframe");
for(var i = 0, len = iframes.length; i<len; i++){
window.frames[i].onload = function(_i){
return function(){
iframes[_i].style.height = window.frames[_i].document.body.scrollHeight + "px";
}
}(i);
}
Работа с jquery под нагрузкой (кросс-браузер):
<iframe src="your_url" marginwidth="0" marginheight="0" scrolling="No" frameborder="0" hspace="0" vspace="0" id="containiframe" onload="loaderIframe();" height="100%" width="100%"></iframe>
function loaderIframe(){
var heightIframe = $('#containiframe').contents().find('body').height();
$('#frame').css("height", heightFrame);
}
на изменение размера в отзывчивой странице:
$(window).resize(function(){
if($('#containiframe').length !== 0) {
var heightIframe = $('#containiframe').contents().find('body').height();
$('#frame').css("height", heightFrame);
}
});
Дэвид Брэдшоу и Крис Джейкоб уже предлагали использовать подход postMessage. И я полностью согласен, что это правильный способ делать такие вещи.
Я просто хочу опубликовать пример, реальный код, который работает, на случай, если для некоторых это будут готовые ответы.
На стороне iframed:
<body onload="docResizePipe()">
<script>
var v = 0;
const docResizeObserver = new ResizeObserver(() => {
docResizePipe();
});
docResizeObserver.observe(document.querySelector("body"));
function docResizePipe() {
v += 1;
if (v > 5) {
return;
}
var w = document.body.scrollWidth;
var h = document.body.scrollHeight;
window.parent.postMessage([w,h], "*");
}
setInterval(function() {
v -= 1;
if (v < 0) {
v = 0;
}
}, 300);
</script>
Обратите внимание на механизм блокировки рекурсии - это было необходимо из-за очевидной ошибки в Firefox, но в любом случае пусть это будет.
На стороне родительского документа:
<iframe id="rpa-frame" src="3.html" style="border: none;"></iframe>
<script>
var rpaFrame = document.getElementById("rpa-frame");
window.addEventListener("message", (event) => {
var width = event.data[0];
var height = event.data[1];
rpaFrame.width = parseInt(width)+60;
rpaFrame.height = parseInt(height)+60;
console.log(event);
}, false);
</script>
Надеюсь, это будет полезно.
не мог найти что-то, что идеально обрабатывало бы большие тексты + большие изображения, но я закончил с этим, кажется, это делает это правильно или почти правильно каждый раз:
iframe.addEventListener("load",function(){
// inlineSize, length, perspectiveOrigin, width
let heightMax = 0;
// this seems to work best with images...
heightMax = Math.max(heightMax,iframe.contentWindow.getComputedStyle(iframe.contentWindow.document.body).perspectiveOrigin.split("px")[0]);
// this seems to work best with text...
heightMax = Math.max(heightMax,iframe.contentWindow.document.body.scrollHeight);
// some large 1920x1080 images always gets a little bit off on firefox =/
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
if(isFirefox && heightMax >= 900){
// grrr..
heightMax = heightMax + 100;
}
iframe.style.height = heightMax+"px";
//console.log(heightMax);
});
Используя jQuery:
parent.html
<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<style>
iframe {
width: 100%;
border: 1px solid black;
}
</style>
<script>
function foo(w, h) {
$("iframe").css({width: w, height: h});
return true; // for debug purposes
}
</script>
<iframe src="child.html"></iframe>
</body>
child.html
<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
$(function() {
var w = $("#container").css("width");
var h = $("#container").css("height");
var req = parent.foo(w, h);
console.log(req); // for debug purposes
});
</script>
<style>
body, html {
margin: 0;
}
#container {
width: 500px;
height: 500px;
background-color: red;
}
</style>
<div id="container"></div>
</body>
Это немного сложнее, поскольку вы должны знать, когда страница iframe загрузилась, что затруднительно, когда вы не контролируете ее содержимое. Можно добавить обработчик загрузки в iframe, но я пробовал это в прошлом, и в браузерах он ведет себя совершенно по-разному (не думаю, кто самый раздражающий...). Возможно, вам придется добавить на страницу iframe функцию, которая выполняет изменение размера, и внедрить некоторый сценарий в контент, который либо прослушивает события загрузки, либо изменяет размер события, который затем вызывает предыдущую функцию. Я думаю добавить функцию на страницу, так как вы хотите убедиться, что она безопасна, но я понятия не имею, насколько легко это будет сделать.
Что-то на линии этого, я верю, должно работать.
parent.document.getElementById(iFrameID).style.height=framedPage.scrollHeight;
Загрузите это с нагрузкой тела на содержание iframe.
У меня есть простое решение, и вы должны определить ширину и высоту в ссылке, попробуйте (это работает с большинством браузеров):
<a href='#' onClick=" document.getElementById('myform').src='t2.htm';document.getElementById('myform').width='500px'; document.getElementById('myform').height='400px'; return false">500x400</a>