?

Log in

No account? Create an account
Previous Entry Share Next Entry
Как динамически изменить высоту кроссдоменного iframe
gennadz

Originally published at web-жизнь и php программирование. You can comment here or there.

Вобщем так.
У меня был один домен. Например domen1.ru.
На нём находится iframe.
iframe брал информацию с другого моего домена. Например domen2.ru
Нужно было динамически изменять высоту iframe в соответствии с содержимым domen2.ru

Стандартными способами т.е. через

document.getElementById('demo_frame').height = document.getElementById('demo_frame').contentWindow.document.body.scrollHeight;

Это решить не удавалось т.к. политика кроссбраузерной передачи данных запрещает обращаться к объекты body на другом домене.

Пришлось как-то выкручиваться. Неоценимую помощь оказала вот эта статья. Со ссылкой на источник опубликую её здесь, в первую очередь для себя, а если кому-то пригодится, буду только рад)

Как известно, при работе с фреймами для обеспечения безопасности браузеры не позволяют JavaScript-коду обращаться со страницы одного домена на страницу другого домена. В этой статье мы рассмотрим аспекты кросс-доменной работы в JavaScript и опишем один из «хороших» частных случаев.

Но вначале я приведу решение задачи автоматического изменения высоты IFRAME, загружаемого с другого домена. (Resize height of an IFRAME from a different domain.)
Автоматическое изменение высоты IFRAME с другого домена

Иногда приходится писать сервисы, которые работают не сами по себе, а вставляют контент на страницы других сервисов в IFRAME. (В основном это разнообразные виджеты.) Но высота IFRAME ограничена значением, которое указано в атрибуте height тэга <iframe> и не увеличивается автоматическ, если контент внутри IFRAME занимает больше места.
Листинг 1: Страница master.com/index.html

...
<iframe src="http://slave.com/frame.html" height="100"></iframe>
какой угодно JS, который мы пишем сами
...

скопировать код в буфер обмена
Листинг 2: Страница slave.com/frame.html

...
//какой угодно код, полностью нам подвластный
...

Проблема: высота slave.com/frame.html может меняться, ее нельзя указать «заведомо» в height IFRAME. Требуется сделать так, чтобы на master.com/index.html крутился какой-то JS, который «подгоняет» высоту IFRAME под контент. Главная сложность – то, что контент находится на другом домене.
Решение: автоматическое установление высоты IFRAME

Кроссбраузерное решение этой задачи приводится ниже. Его особенности:
не портится history браузера;
работает даже в Опере 7 и IE6;
для ускорения работы высота фрейма всегда делается кратной N=30 пикселям.

Фактически, там два алгоритма: для IE (через location.hash) и для «не-IE» (через window.name и «простукивание» возможных высот в цикле). См. также комментарии к статье на Хабрахабре, там разъяснения, почему сделано так, а не иначе.
Листинг 3: РЕШЕНИЕ: страница master.com/index.html

<body>
<iframe
src="http://slave.com/frame.html" height="150"
style="padding:0; margin:0" scrolling="no"
onload="var th=this; setTimeout(function() {
var h=null;
if (!h) if (location.hash.match(/^#h(\d+)/)) h=RegExp.$1;
if (!h) for (var i=0; i<10000; i+=30) if (top.frames['h'+i]) { h=i; break; }
if (h) th.style.height=h+'px';
}, 10)"
></iframe>
</body>

Листинг 4: РЕШЕНИЕ: страница slave.com/frame.html

<html>
<style>
html, body { padding: 0; margin: 0; }
</style>
<body>
Header.
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
Footer.
<script>
window.onload = function() {
var h = Math.ceil(document.body.scrollHeight / 30) * 30;
var ie = 0 /*@cc_on + @_jscript_version @*/;
if (!ie) window.name = "h" + h;
else top.location.replace("http://master.com/#h" + h);
}
</script>
</body>
</html>

Внимательный читатель заметит, что на странице slave.com/frame.html мы должны обладать знанием о том, откуда загрузили данную страницу. Т.е. нужно получить значение «http://master.com» (в демонстрационном листинге я для простоты вставил это значение вручную). Средствами только JavaScript этого сделать не получится, т.к. скрипт внутри IFRAME не имеет доступа к родительскому окну и не может прочитать его адрес. Тем не менее, вы всегда можете передать адрес родительского окна внутрь IFRAME через обыкновенный GET-параметр: <iframe src=»http://slave.com/iframe.html?ret=http://master.com/» >
Общий случай запрещенной операции по кроссдоменному доступу

Например, у нас есть вот такая конструкция:
Листинг 5: Страница master.com/index.html

...
<iframe src="http://slave.com/frame.html"></iframe>
какой угодно JS, который мы пишем сами
...

скопировать код в буфер обмена
Листинг 6: Страница slave.com/frame.html

...
//какой угодно код, полностью нам подвластный
...

Не существует способа, который бы позволял JS-коду в slave.com/frame.html обратиться к данным (или запустить функцию) страницы master.com/index.html, а также наоборот.

Правда, из этого правила есть одно важное исключение: внутри slave.com/frame.html можно присваивать значение top.location и осуществлять, таким образом, редиректы окна верхнего уровня куда-то еще.
И все-таки есть хак для прямых поддоменов

Кросс-доменный обмен все же возможен, если одна страница находится на прямом поддомене другой. В этом случае необходимо провести следующие магические операции:
Листинг 7: Страница master.com/index.html

...
<iframe src="http://subdomain.master.com/frame.html" height="100"></iframe>
<script>
document.domain = document.domain; // да-да, это обязательно нужно, иначе не заработает
// или можно напрямую написать: document.domain = "master.com", хотя это и не так весело
</script>
...

Листинг 8: Страница subdomain.master.com/frame.html
...
<script>
document.domain = "master.com";
</script>
...

Т.е. мы должны в обеих страницах присвоить свойству document.domain одинаковое значение, равное «родительскому» домену. Тогда обращение внутрь (или наружу) IFRAME возможно. Еще раз подчеркиваю, что это работает только в случае, если один домен является прямым поддоменом другого (именно прямым, потому что даже abc.subdomain.master.com здесь уже не сработает).