Одной из самых сложных проблем в моем опыте работы с javascript было правильное (то есть «кроссбраузерное») вычисление высота iframe. В моих приложениях у меня много динамически генерируемых iframe, и я хочу, чтобы все они выполняли своего рода автоматическое изменение размера в конце события загрузки, чтобы настроить их высоту и ширину.
В случае вычислений высота моим лучшим решением является следующее (с помощью jQuery):
function getDocumentHeight(doc) {
var mdoc = doc || document;
if (mdoc.compatMode=='CSS1Compat') {
return mdoc.body.offsetHeight;
}
else {
if ($.browser.msie)
return mdoc.body.scrollHeight;
else
return Math.max($(mdoc).height(), $(mdoc.body).height());
}
}
Я безуспешно искал в Интернете. Я также протестировал библиотеку Yahoo, в которой есть несколько методов для измерения размеров документа и области просмотра, но это меня не удовлетворило.
Мое решение работает прилично, но иногда рассчитывает более высокую высоту.
Я изучил и протестировал множество свойств, касающихся высоты документа в Firefox / IE / Safari: documentElement.clientHeight, documentElement.offsetHeight, documentElement.scrollHeight, body.offsetHeight, body.scrollHeight, ...
Также jQuery не имеет последовательного поведения в различных браузерах с вызовами $(document.body).height(), $('html', doc).height(), $(window).height().
Я вызываю указанную выше функцию не только в конце события загрузки, но и в случае динамически вставленных элементов DOM или элементов, скрытых или отображаемых. Это случай, который иногда нарушает код, работающий только в событии загрузки.
Есть ли у кого-нибудь реальное кроссбраузерное решение (по крайней мере, Firefox / IE / Safari)? Несколько советов или подсказок?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Хотя мне нравится ваше решение, я всегда считал, что IFRAME доставляют больше проблем, чем они того стоят.
Почему ? 1. Проблема калибровки. 2. В iframe есть атрибут src, о котором нужно беспокоиться. то есть абсолютный путь. 3. Дополнительная сложность со страницами.
Мое решение - DIV, которые динамически загружаются через вызовы AJAX. DIV будут автоматически изменять размер. Хотя код AJAX требует работы с javascript (что можно сделать с помощью фреймворков), они зависят от местоположения сайта. 3 - это промывка, вы торгуете сложностью на страницах вплоть до javascript.
Вместо <IFRAME ...> используйте <DIV id = "mystuff" />
Выполните вызов ajax, чтобы заполнить div mystuff данными и позволить браузеру позаботиться об этом.
Я рассматривал возможность DIV, но я не знаю простого решения проблемы идентификатора (элементов DOM): при совместном использовании одного и того же пространства имен DIV, вероятно, имеет много конфликтов идентификаторов. Учтите, что у меня одновременно открыто много фреймов. Тем не менее, ваше решение заслуживает внимательного рассмотрения.
Вы не можете AJAX загружать контент с внешнего сайта; это нарушение безопасности браузера (межсайтовый скриптинг). <iframes>, вероятно, единственное клиентское решение, позволяющее загружать внешний контент.
Очень хорошее замечание об элементах x-site, однако, если мне действительно нужны эти данные, я "перекидываю" их с сервера. т.е. страница выполняет вызов, сервер выполняет построение страницы, включая другие «внешние» страницы, а затем возвращает это исходному клиенту. У меня был клиент, которому требовалось встроенное видео, и, чтобы избежать межсайтового взаимодействия, сервер временно сохранил его и вернул все клиенту.
@jim - моя проблема с этим подходом заключается в том, что я загружаю HTML, который может быть, а может и не быть полуразрушенным. Использование iframe ограничивает влияние плохой разметки на остальную часть страницы.
Вы можете загружать данные из другого домена с помощью JSONP.
iFrames де-факто являются стандартом для загрузки рекламы Google, Yahoo, Microsoft, Doubleclick и тысяч других компаний.
@Stephen - То, что есть «тысячи» других, не означает, что решение подходит для того, что вы пытаетесь сделать. Посмотрите на cpmadvisors.com/2009/11/16/…, чтобы узнать о том, как Amazon обертывает фреймы рекламных сетей, чтобы предотвратить сбор данных.
Вот решение, которое, кажется, работает. По сути, scrollHeight является правильным значением в большинстве случаев. Однако в IE (в частности, 6 и 7), если контент просто содержится в текстовых узлах, высота не вычисляется и по умолчанию используется только высота, установленная в CSS или в атрибуте «высота» в iframe. Это было найдено методом проб и ошибок, так что принимайте это как следует.
function getDocumentHeight(doc) {
var mdoc = doc || document;
var docHeight = mdoc.body.scrollHeight;
if ($.browser.msie) {
// IE 6/7 don't report body height correctly.
// Instead, insert a temporary div containing the contents.
var child = $("<div>" + mdoc.body.innerHTML + "</div>", mdoc);
$("body", mdoc).prepend(child);
docHeight = child.height();
child.remove();
}
return docHeight;
}
Я нашел, что это решение работает, например, 6+, ff 3.5+, safari 4+. Я создаю и добавляю в документ iframe. Следующий код выполняется в конце события загрузки jQuery после некоторой другой манипуляции с dom. Тайм-аут нужен мне из-за дополнительных манипуляций с dom, происходящих в событии загрузки.
// sizing - slight delay for good scrollheight
setTimeout(function() {
var intContentHeight = objContentDoc.body.scrollHeight;
var $wrap = $("#divContentWrapper", objContentFrameDoc);
var intMaxHeight = getMaxLayeredContentHeight($wrap);
$this.height(intContentHeight > intMaxHeight ? intMaxHeight : intContentHeight);
// animate
fireLayeredContentAnimation($wrap);
}, 100);
У меня есть некоторые ограничения по размеру, которые нужно учитывать, и это то, что для меня проверяет вызов getMaxLayeredContentHeight. Надеюсь, это поможет.
Поскольку в вашем примере вы обращаетесь к документу внутри в IFRAME, я думаю, вы говорите о знании высоты документа, а не самого фрейма. Кроме того, это означает, что контент поступает с вашего собственного веб-сайта, и вы можете контролировать его содержимое.
Итак, почему бы вам просто не разместить DIV вокруг своего контента, а затем использовать clientHeight этого DIV?
Код, который вы загружаете в свой IFRAME:
...
<body>
<div id = "content">
...
</div>
</body>
Родительский документ:
function getDocumentHeight(mdoc) {
return mdoc.getElementById("content").clientHeight;
}
Кстати, эта часть вашей примерной функции не имеет смысла, поскольку «документ» не относится к IFRAME:
var mdoc = doc || document;
Вот сценарий, который изменяет размер iFrame в зависимости от высоты тела внутри него.
Некоторое время не было принятого ответа, поэтому я хотел внести свой вклад в решение, к которому я пришел после некоторых исследований. Это кроссбраузерный и междоменный (например, когда iframe указывает на контент из другого домена)
В итоге я использовал механизм передачи сообщений html5, завернутый в подключение jQuery, что делает его совместимым со старыми браузерами с использованием различных методов (некоторые из них описаны в этом потоке).
Конечное решение очень простое.
На главной (родительской) странице:
// executes when a message is received from the iframe, to adjust
// the iframe's height
$.receiveMessage(
function( event ){
$( 'my_iframe' ).css({
height: event.data
});
});
// Please note this function could also verify event.origin and other security-related checks.
На странице iframe:
$(function(){
// Sends a message to the parent window to tell it the height of the
// iframe's body
var target = parent.postMessage ? parent : (parent.document.postMessage ? parent.document : undefined);
$.postMessage(
$('body').outerHeight( true ) + 'px',
'*',
target
);
});
Я тестировал это на Chrome 13+, Firefox 3.6+, IE7, 8 и 9 на XP и W7, safari на OSX и W7. ;)
Сейчас я работаю над этим вопросом. Вы нашли решение?