Тема невозможности взаимодействия между родительской страницей и кроссдоменным iframe является настолько часто обсуждаемой на различных ресурсах по web-разработке, что пора включать ее в F.A.Q.
Юмор в том, что решение на удивление простое, является очень корректным методом, а не хаком и лежит на поверхности: для всех современных браузеров, в том числе для IE, начиная с 8-го существует метод window.postMessage и событие window.onmessage, через которые возможна передача сообщений как между iframe и родителем, так и в дочернее окно, вызванное при помощи window.open.
Об этом, кстати, пишет Илья Кантор (javascript.ru). У него хорошо описано как передать сообщение из родителя в iframe. Мне же пришлось решить обратную задачу - передать сообщение из iframe в родительскую страницу. Цель тоже часто встречается в сети в виде вопросов - «Как сделать iframe той же высоты, что и его содержимое, чтобы не было прокрутки»:
В документе, загружающемся в iframe всё еще проще (html не привожу, только скрипт):
Способ этот входит в спецификацию HTML5 и он настолько приятен, что его хочется использовать не только в кросс-доменном варианте, но и просто когда нужно организовать общение между разными страницами.
Юмор в том, что решение на удивление простое, является очень корректным методом, а не хаком и лежит на поверхности: для всех современных браузеров, в том числе для IE, начиная с 8-го существует метод window.postMessage и событие window.onmessage, через которые возможна передача сообщений как между iframe и родителем, так и в дочернее окно, вызванное при помощи window.open.
Об этом, кстати, пишет Илья Кантор (javascript.ru). У него хорошо описано как передать сообщение из родителя в iframe. Мне же пришлось решить обратную задачу - передать сообщение из iframe в родительскую страницу. Цель тоже часто встречается в сети в виде вопросов - «Как сделать iframe той же высоты, что и его содержимое, чтобы не было прокрутки»:
<html> <head> </head> <body> </body> </html>
// Эта конструкция jQuery вызывается по завершении построения DOM $(function(){ var frame = $('#test'); var height = 0; var listener = function(event){ // В более серьезных задачах вам придется делать фильтрацию // по имени домена (origin) или самим данным (data) height = parseInt(event.data); // Только если новая высота не совпадает с прежней if (height != frame.height()) frame.css('height', height); } // jQuery не умеет работать с postMessage из коробки - вешаем событие // стандартными средствами function addEvent(elem, evnt, func) { if (elem.addEventListener) { // W3C DOM elem.addEventListener(evnt,func,false); } else if (elem.attachEvent) { // IE DOM elem.attachEvent("on"+evnt, func); } else { elem["on"+evnt] = func; } } addEvent (window, "message", listener); // вешаем событие изменения высоты на событие полной загрузки содержимого фрейма frame.bind('load', setheight); });
В документе, загружающемся в iframe всё еще проще (html не привожу, только скрипт):
// $(window).load вызывается когда загружены все картинки, а так как от них // зависит высота страницы - нужно учитывать. $(window).load(function(){ var $doc = $(document); var height = 0; var sendHeight = function(){ // проверяем, изменилась ли высота if ($doc.height() != height) { // если да - изменяем глобальную переменную и отправляем ее родителю height = $doc.height(); parent.postMessage(height, '*'); } } sendHeight(); // если высота будет меняться уже после загрузки фрейма - будет вылано новое значение window.onresize = sendHeight; });
Способ этот входит в спецификацию HTML5 и он настолько приятен, что его хочется использовать не только в кросс-доменном варианте, но и просто когда нужно организовать общение между разными страницами.
Привет!
ОтветитьУдалитьСпасибо за статью, весьма познавательно. Только есть один вопросик: что если во фрейм должен загружаться не .html-документ, а .php-файл? Как быть в этом случае? Если я правильно понял - то последний скрипт надо вставлять именно в дочерний документ, который будет грузиться во фрейм?
Откуда в parent.js берется setheight?
ОтветитьУдалить