изменение размера междоменного фрейма - PullRequest
83 голосов
/ 06 мая 2011

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

-Edit

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

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

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


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

3 фрейма

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

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

http://css -tricks.com / примеры / iFrameResize / crossdomain.php # frameId = кадр один и высота = * 1030 тысяча сто семьдесят-девять *

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

Я нашел еще один пост о том, как использовать высоту прокрутки, чтобы попытаться изменить размер формы ... теоретически это работает хорошо, но я не мог применить его должным образом, используя высоту прокрутки 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 нет ничего enter image description here

Теперь, как chrome это вычисляет? (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 </p>

http://maxq.tigris.org/


РЕДАКТИРОВАТЬ 09-2013 UPDATE

Все это можно сделать с помощью сокетов 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 ]

23 голосов
/ 22 марта 2013

Подобно тому, что упоминал Шон, вы можете использовать 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>

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

Лучший, Бейкер

10 голосов
/ 06 мая 2011

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

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

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

6 голосов
/ 18 июня 2013

Изучив множество различных решений, я написал простую небольшую библиотеку, чтобы учесть множество различных вариантов использования. Поскольку мне нужно было решение, которое поддерживало бы несколько пользовательских сгенерированных 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
        );
    }
});
0 голосов
/ 05 января 2018

HTTPS другая ссылка возвращает высоту для автоматического увеличения iframe

https: //-a.com content:

 <!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 WORK

xcom https> ycom https WORK

xcom http> ycom http WORK

xcom https> ycom http WORK

Test Work Screenshot

0 голосов
/ 12 марта 2016

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

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

0 голосов
/ 02 апреля 2015

В настоящее время я знаю только 4 решения:

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

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

0 голосов
/ 10 января 2014

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

это идет в голову: (это было написано для сценария 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 и имя в скрипте в заголовке, и альт! у вас на одной странице есть несколько изменителей размера ... это работает очень хорошо!

есть phun.

0 голосов
/ 03 декабря 2011

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

$(window).height();

и используйте его в качестве атрибута высоты iframe.

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

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

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

setInterval(getDocHeight, 1);

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

0 голосов
/ 06 мая 2011

Ищете высоту страницы, содержащейся в iframe?У меня есть некоторый работающий javascript, который проверяет высоту содержимого iframe, а затем устанавливает высоту iframe на высоту содержимого.

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

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

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

...