Междоменное изменение размера iframe

Как изменить размер фрейма из другого домена

-Редактировать

Прокрутите вниз для некоторых решений.. или прочитайте о том, как НЕ сделать этого:D

После многих часов взлома кода - вывод состоит в том, что все внутри iframe недоступно, даже полосы прокрутки, которые отображаются на моем домене. Я перепробовал много техник безрезультатно.

Чтобы сэкономить время, даже не идите по этому пути, просто используйте sendMessages для междоменной связи. Есть плагины для HTML < 5, которые я использую - перейдите к основанию для хорошего примера:)


Последние несколько дней я пытался интегрировать iframe в сайт. Это краткосрочное решение, в то время как другая сторона разрабатывает и API(это может занять месяцы...) И поскольку это как краткосрочное решение, которое мы действительно хотим использовать easyXDM, у меня есть доступ к другому домену, но достаточно сложно попросить их добавить заголовок p3p как есть.....

3 кадра

Самым близким решением, которое я нашел, было 3 фрейма, но оно напоминает хром и сафари, поэтому я не могу его использовать.

открыть в хроме

http://css-tricks.com/examples/iFrameResize/crossdomain.php

Измерьте полосы прокрутки

Я нашел еще один пост о том, как использовать высоту прокрутки, чтобы попытаться изменить размер формы... теоретически это работает хорошо, но я не мог применить его правильно, используя высоту прокрутки iframes..

document.body.scrollHeight

То, что obvoisly использует высоту тел (не может получить доступ к этим свойствам, 100% основано на отображении клиентов, а не на высоте документа x-domains)

Я пытался использовать jquery, чтобы получить высоту iframes

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight

возвращаемые значения отличаются по хрому и т. д. - или просто не имеют смысла вообще. Проблема в том, что все внутри фрейма запрещено - даже полоса прокрутки...

Компьютерные стили

Но если я проверяю и вставляю элемент chrome в iframe, он показывает мне размеры документов внутри iframe (используя jquery x-domain для получения iframe.heigh - доступ запрещен) В вычисленном CSS ничего нет

Теперь, как хром рассчитывает это? (edit- browser повторно отображает страницу, используя встроенный движок рендеринга, чтобы вычислить все эти настройки - но нигде не прикреплен, чтобы предотвратить междоменное мошенничество.. так..)

HTML4

Я прочитал спецификацию HTML4.x и там сказано, что должны быть доступны только для чтения значения через document.element, но доступ запрещен через jquery

Прокси-фрейм

Я пошел по пути прокси сайта обратно и вычислил, что все в порядке... пока пользователь не войдет в систему через iframe и прокси не получит страницу входа вместо реального контента. Также для некоторых, заходящих на страницу дважды не допускается

http://www.codeproject.com/KB/aspnet/asproxy.aspx

http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/

Перерисовать страницу

Я не зашел так далеко, но есть движки jscript, которые будут смотреть на исходный код и перерисовывать страницу на основе исходного файла. но это потребовало бы взлома этих jscripts.. и это не идеальная ситуация для коммерческих объектов... и некоторые из них включают чистые Java-апплеты или рендеринг на стороне сервера

http://en.wikipedia.org/wiki/Server-side_JavaScript

http://htmlunit.sourceforge.net/ <-java не jscript

http://maxq.tigris.org/


РЕДАКТИРОВАТЬ 09-2013ОБНОВЛЕНИЕ

Все это можно сделать с помощью HTML5-сокетов. Но easyXDM отлично подходит для страниц жалоб, не относящихся к HTML5.

Решение 1 Очень отличное решение!

Использование easyXDM

На вашем сервере вы создали страницу в виде

<html>
<head>
<script src="scripts/easyXDM.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">

    var transport = new easyXDM.Socket(/** The configuration */{
    remote: "http://www.OTHERDOMAIN.com/resize_intermediate.html?url=testpages/resized_iframe_1.html",

    //ID of the element to attach the inline frame to
    container: "embedded",
    onMessage: function (message, origin) {
        var settings = message.split(",");
        //Use jquery on a masterpage.
        //$('iframe').height(settings[0]);
        //$('iframe').width(settings[1]);

        //The normal solution without jquery if not using any complex pages (default)
        this.container.getElementsByTagName("iframe")[0].style.height = settings[0];
        this.container.getElementsByTagName("iframe")[0].style.width = settings[1];
    }
});

</script>

</head>

<body>
    <div id="embedded"></div>
</body>

а в домене вызывающих абонентов им просто нужно добавить intermiedate_frame html и easyXDM.js в одно и то же место. Как родительская папка - тогда вы можете получить доступ к относительным каталогам или отдельной папке только для вас.

ОПЦИЯ 1

Если вы не хотите добавлять сценарии на все страницы, посмотрите вариант 2!

Затем они могут просто добавить простой jscript в конец каждой страницы, для которой необходимо изменить размер. Не нужно включать easyxdm на каждой из этих страниц.

 <script type="text/javascript">
            window.onload = function(){ parent.socket.postMessage( (parseInt(document.body.clientHeight)) + "," + ( document.body.clientWidth ) );  };
        </script>

Я изменил параметры, которые он отправляет. Если вы хотите, чтобы ширина работала правильно, тогда страницы на другом домене должны включать ширину страницы в стиле, где-то похожем на:

<style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                background-color: rgb(75,0,85);
                color:white;
                width:660px
            }
            a {
            color:white;
            visited:white;
            }
        </style>

Это прекрасно работает для меня. Если ширина не включена, то рамка ведет себя немного странно, и kind'of пытается угадать, что это должно быть.. и не будет уменьшаться, если вам это нужно.

ВАРИАНТ 2

Измените промежуточный кадр, чтобы опросить изменения

Ваша промежуточная рамка должна выглядеть примерно так...

    <!doctype html>
<html>
    <head>

        <title>Frame</title>
        <script type="text/javascript" src="easyXDM.js">
        </script>
        <script type="text/javascript">
            var iframe;
            var socket = new easyXDM.Socket({
                //This is a fallback- not needed in many cases
                swf: "easyxdm.swf",
                onReady: function(){
                    iframe = document.createElement("iframe");
                    iframe.frameBorder = 0;
                    document.body.appendChild(iframe);
                    iframe.src = "THE HOST FRAME";
            iframe.onchange = messageBack();

                },
                onMessage: function(url, origin){
                    iframe.src = url;
                }
            });

            //Probe child.frame for dimensions.
            function messageBack(){
                socket.postMessage ( iframe.contentDocument.body.clientHeight + "," + iframe.contentDocument.body.clientWidth); 
            };

            //Poll for changes on children every 500ms.
            setInterval("messageBack()",500); 

        </script>
        <style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                width: 100%;
                height: 100%;
            }

            iframe {
                width: 100%;
                height: 100%;
                border: 0px;
            }
        </style>
    </head>
    <body>

    </body>
</html>

Интервал можно сделать более эффективным, чтобы проверить, если размер изменился, и отправлять, только если изменяются размеры, вместо отправки сообщений каждые 500 мс. Если вы реализуете эту проверку, вы можете изменить опрос всего за 50 мс! повеселись


Работайте в разных браузерах и быстро. Отличные функции отладки!

Excellent Work to  Sean Kinsey  who made the script!!!

Решение 2 (работает, но не отлично)

Поэтому, если у вас есть взаимное соглашение с другим доменом, вы можете добавить библиотеку для обработки sendmessage. Если у вас нет доступа к другому домену. Продолжайте искать больше взломов, потому что я не смог найти или полностью оправдать их, я нашел.

Таким образом, другой домен включит их в тег Head

<script src="scripts/jquery-1.5.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery.postmessage.min.js" type="text/javascript"></script>
<script src="scripts/club.js" type="text/javascript"></script>

В club.js есть только некоторые пользовательские вызовы, которые я сделал для изменения размера вызовов и содержит..

 $(document).ready(function () {   
    var parent_url = decodeURIComponent( document.location.hash.replace( /^#/, '' ) ),link;
//Add source url hash to each url to authorise callback when navigating inside the frame.Without this clicking any links will break the communication and no messages will be received
$('a[href]').each(function(){ 
     this.href = this.href + document.location.hash ;
});
//Get the dimensions and send back to calling page.
var h1 = document.body.scrollHeight;
var w1 = document.body.scrollWidth;
$.postMessage({ if_height: h1, if_width: w1 }, parent_url, parent );
  });

И ваша страница будет выполнять всю тяжелую работу и имеет хороший сценарий...

  //This is almost like request.querystring used to get the iframe data
  function querySt(param, e) {
         gy = e.split("&");
         for (i = 0; i < gy.length; i++) {
             ft = gy[i].split("=");
             if (ft[0] == param) {
                 return ft[1];
             }
         }
     }


     $(function () {
         // Keep track of the iframe dimensions.
         var if_height;
         var if_width;
         // Pass the parent page URL into the Iframe in a meaningful way (this URL could be
         // passed via query string or hard coded into the child page, it depends on your needs).
         src = 'http://www.OTHERDOAMIN.co.uk/OTHERSTARTPAGE.htm' + '#' + encodeURIComponent(document.location.href),
         // Append the Iframe into the DOM.
         iframe = $('<iframe " src="' + src + '" width="100%" height="100%" scrolling="no" frameborder="0"><\/iframe>').appendTo('#iframe');

         // Setup a callback to handle the dispatched MessageEvent event. In cases where
         // window.postMessage is supported, the passed event will have .data, .origin and
         // .source properties. Otherwise, this will only have the .data property.
         $.receiveMessage(function (e) {
             // Get the height from the passsed data.
             //var h = Number(e.data.replace(/.*if_height=(\d+)(?:&|$)/, '$1'));
             var h = querySt("if_height", e.data);
             var w = querySt("if_width", e.data);


             if (!isNaN(h) && h > 0 && h !== if_height) {
                 // Height has changed, update the iframe.
                 iframe.height(if_height = h);
             }
             if (!isNaN(w) && w > 0 && w !== if_width) {
                 // Height has changed, update the iframe.
                 iframe.width(if_width = w);
             }
             //For debugging only really- can remove the next line if you want
             $('body').prepend("Recieved" + h + "hX" + w + "w .. ");
             // An optional origin URL (Ignored where window.postMessage is unsupported).
           //Here you must put the other domain.com name only! This is like an authentication to prevent spoofing and xss attacks! 
         }, 'http://www.OTHERDOMAIN.co.uk');
     });

ВАРИАНТ 3

В настоящее время это небольшая библиотека JS для управления изменением размера междоменных iFrames, для которой по-прежнему требуется, чтобы в iFrame было немного JavaScript, однако это всего лишь 2,8 Кб (765 байт в сжатом виде) собственного JS, который не имеет каких-либо зависимостей. и он ничего не делает, пока не будет вызван родительской страницей. Это означает, что это хороший гость в системах других людей.

Этот код использует mutationObserver для обнаружения изменений DOM, а также отслеживает события изменения размера, так что размер iFrame остается равным размеру содержимого. Работает в IE8 +.

https://github.com/davidjbradshaw/iframe-resizer

9 ответов

Решение

Дело в том, что для этого нет другого способа, кроме использования междоменного обмена сообщениями, поскольку вам нужно получить вычисленную высоту документа в одном домене и документа в другом домене.

Итак, либо вы делаете это с помощью postMessage (работает во всех современных браузерах), или вы тратите 5 минут на адаптацию примера изменения размера iframe из easyXDM.

Другой стороне действительно нужно скопировать несколько файлов в свой домен и добавить одну строку кода в свой документ.

Подобно тому, что упоминал Шон, вы можете использовать postMessage. Я потратил так много времени, пытаясь изменить способы изменения размера iframe с помощью междоменного домена, но не повезло, пока я не наткнулся на эту замечательную запись в блоге Дэвида Уолша: http://davidwalsh.name/window-iframe

Это комбинация моего кода и решения Дэвида. Мое решение направлено именно на изменение размера фреймов.

На дочерней странице найдите высоту страницы и передайте ее на родительскую страницу (которая содержит фрейм). Замените element_id на свой идентификатор элемента (html, body, что угодно).

<script>
function adjust_iframe_height(){
    var actual_height = document.getElementById('element_id).scrollHeight;
    parent.postMessage(actual_height,"*"); 
    //* allows this to post to any parent iframe regardless of domain
}
</script>

<body onload="adjust_iframe_height();"> 
//call the function above after the content of the child loads

В родительском окне добавьте этот код. Замените iframe_id на свой идентификатор iframe:

<script>
// Create IE + others compatible event handler
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

// Listen to message from child window
eventer(messageEvent,function(e) {
  console.log('parent received message!:  ',e.data);
  document.getElementById('iframe_id').height = e.data + 'px';
},false);
</script>

Если вы откроете консоль, вы увидите высоту печати в журнале консоли. Это поможет вам в отладке, поэтому я оставил его там.

Бест, Бейкер

Посмотрев множество разных решений, я написал простую небольшую библиотеку, чтобы учесть множество различных вариантов использования. Поскольку мне требовалось решение, которое поддерживало бы несколько пользовательских сгенерированных iFrames на странице портала, поддерживаемые размеры браузера и могли справляться с загрузкой JavaScript на главной странице после iFrame. Я также добавил поддержку изменения размера в width и функцию обратного вызова и разрешил переопределение body.margin, так как вы, вероятно, захотите, чтобы этот параметр был установлен на ноль.

https://github.com/davidjbradshaw/iframe-resizer

Код iframe - это всего лишь небольшой автономный JavaScript, поэтому он является хорошим гостем на страницах других людей.

Затем сценарий инициализируется на странице хоста со следующими доступными параметрами.

iFrameResize({
    log                    : true,  // For development
    autoResize             : true,  // Trigering resize on events in iFrame
    contentWindowBodyMargin: 8,     // Set the default browser body margin style (in px)
    doHeight               : true,  // Calculates dynamic height
    doWidth                : false, // Calculates dynamic width
    enablePublicMethods    : true,  // Enable methods within iframe hosted page 
    interval               : 32,    // interval in ms to recalculate body height, 0 to disable refreshing
    scrolling              : false, // Enable the scrollbars in the iFrame
    callback               : function(messageData){ // Callback fn when message is received
        $('p#callback').html(
            '<b>Frame ID:</b> '    + messageData.iframe.id +
            ' <b>Height:</b> '     + messageData.height +
            ' <b>Width:</b> '      + messageData.width + 
            ' <b>Event type:</b> ' + messageData.type
        );
    }
});

Вы смотрели на атрибуты HTML5 "подгонка объекта"? Масштабирование видео / изображений в iframe, а не масштабирование iframe (хорошо, если вы захватите изображение среднего размера, ширина которого 5000 пикселей). Опция "fit" (другие - "cover" и "fill") использует подход типа "почтовый ящик", чтобы соответствовать источнику, сохраняя при этом пропорции. Для просмотра без HTML5, похоже, есть много доступных полифилов. Это замечательно, но ошибка на краю Edge делает его несовместимым с Microsoft New Nightmare уже около года, сейчас: https://github.com/anselmh/object-fit

РЕДАКТИРОВАТЬ: Чтобы обойти междоменные проблемы, вы всегда можете просто выполнить работу в скрипте содержимого расширения Chrome, так как он считает, что это часть страницы, на которую вы вставляете свой iframe.

На сегодняшний день я знаю только 4 решения:

Только третий может решить многие проблемы. Например, вы можете создать отзывчивый iFrame; закройте его изнутри или вы можете общаться с ним. Но для этого вам нужен iFrame в Iframe и обходной путь "сторонних файлов cookie" (необязательно).

Я создал статью об этом с примером: междоменный iFrame, управляемый событиями

Вместо использования scroll=no в iframe я изменяю его на "auto". Затем я получаю размер фактического окна

$(window).height();

и использовать это как атрибут высоты iframe.

Ну, результат...

У нас никогда не будет свитка "страницы", только свиток "iframe". Когда вы перемещаетесь, не имеет значения, кто является свитком, но важно то, что есть только 1.

Ну, проблема в том, что пользователь просто меняет размер окна во время навигации. Чтобы решить это, я использую:

setInterval(getDocHeight, 1);

Вы думаете, что это решение вызовет какие-либо ошибки? Это работает для меня, и на iFrame у меня был динамический контекст, сгенерированный php. Я боюсь будущих ошибок с этим...

HTTPS еще одна ссылка, чтобы получить высоту, чтобы iframe autoheight

https://-a.com/ содержание:

 <!DOCTYPE html>
    <html>
    <head>
        <title>Test Page</title>
    </head>
    <body>
        Test Page:
        <hr/>
        <iframe id="iframe" src="https://-b.com" style="width:100%;min-height:600px;border:none;" scrolling="no" ></iframe>
        <script>
        // browser compatibility: get method for event 
        // addEventListener(FF, Webkit, Opera, IE9+) and attachEvent(IE5-8)
        var myEventMethod = 
            window.addEventListener ? "addEventListener" : "attachEvent";
        // create event listener
        var myEventListener = window[myEventMethod];
        // browser compatibility: attach event uses onmessage
        var myEventMessage = 
            myEventMethod == "attachEvent" ? "onmessage" : "message";
        // register callback function on incoming message
        myEventListener(myEventMessage, function (e) {
            // we will get a string (better browser support) and validate
            // if it is an int - set the height of the iframe #my-iframe-id
            if (e.data === parseInt(e.data)) 
                document.getElementById('iframe').height = e.data + "px";
        }, false);
        </script>
    </body>
    </html>

https://-b.com/ содержание iframe:

<!DOCTYPE html>
<html>
<head>
    <title>Test Iframe Content</title>
    <script type="text/javascript">
    // all content including images has been loaded
    window.onload = function() {
        // post our message to the parent
        window.parent.postMessage(
            // get height of the content
            document.body.scrollHeight
            // set target domain
            ,"*"
        )
    };
</script>
</head>
<body>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>1
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>2
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>3
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>4
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>5
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>6
</body>
</html>

Рабочий стол:

xcom http> ycom https РАБОТА

xcom https > ycom https РАБОТА

xcom http> ycom http WORK

xcom https> ycom http WORK

Скриншот тестовой работы

Чтобы изменить размер фрейма, вот простой скрипт:

это идет в голову: (это было написано для сценария php, для html, измените 'на' и \ 'на'...

<script type='text/javascript'>
<!--
function resizeIframe(id){
/*
this.obj=obj
//this.obj.width=null
//this.obj.width=window.frames[\"sizeframe1\"].document.body.scrollWidth
this.obj.style.height=\"\" // for Firefox and Opera
setTimeout(\"this.obj.style.height=this.obj.contentWindow.document.body.scrollHeight+(notIE?heightOffset:0)\",10) // setTimeout required for Opera
*/

el=document.getElementById(id)
el.style.height='200px' // for Firefox and Opera
setTimeout('el.style.height=el.contentWindow.document.body.scrollHeight+\"px\"',1) // setTimeout required for Opera
}

// -->
</script>"

конец головы

это идет в теле (помните, это было написано для сценария php, для html измените все 'на' и \ 'на'...)

<iframe onload='resizeIframe(this.id)' allowTransparency=\"true\" name='ccpaymentwindow' id='sizeframe1' marginwidth='1' marginheight='1' height='700' width='690' border='0' frameborder='1' scrolling='no' src='ccmslink.php?variable1=" . $variable1 . "'></iframe>

Бонус: есть некоторые подсказки выше. Так как он установлен для сценариев php, вы можете сделать с ним многое... узнать больше, сделать больше...

ключом к этому является "sizeframe1" .... для нескольких "resizers" на одной странице, скопируйте один и тот же сценарий, но измените идентификатор в iframe и имя в сценарии в заголовке, и альт! у вас есть несколько ресайзеров на одной странице... это работает очень хорошо!

есть фан.

Вы хотите найти высоту страницы, содержащейся в iframe? Я получил некоторый работающий JavaScript, который проверяет высоту содержимого iframe, а затем устанавливает высоту iframe на высоту содержимого.

var Height = document.getElementById('iFrameId').contentWindow.document.body.scrollHeight;

document.getElementById('iFrameId').height = Height;

Однако это работает, только если страница, которую вы показываете в iframe, находится в том же домене. Если это не так, вы не можете получить доступ к необходимой информации. Следовательно, в доступе отказано в ошибке.

Другие вопросы по тегам