Чи працює авторезинатор висоти міждоменного iframe висоти?


110

Я спробував кілька рішень, але не вдався. Мені цікаво, чи є рішення там, бажано, з простим підручником.


2
Які рішення ви спробували, що були невдалими?
Ізмір Рамірес

1
Я спробував це, але він вироджується у веб-браузерах, як зазначено у статті: css-tricks.com/cross-domain-iframe-resizing Був ще один, але я не можу згадати URL-адресу.
J82


Відповіді:


68

У вас є три варіанти:

1. Використовуйте iFrame-Resizer

Це проста бібліотека для збереження розміру iFrames відповідно до їх вмісту. Він використовує API PostMessage та MutationObserver, із зворотним доступом до IE8-10. У нього також є можливість на сторінці вмісту запитувати, що містить iFrame певного розміру, а також може закрити iFrame, коли ви закінчили з ним.

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

2. Використовуйте Easy XDM (PostMessage + Flash комбо)

Easy XDM використовує набір хитрощів для ввімкнення міждоменного зв’язку між різними вікнами у ряді браузерів, і є приклади його використання для зміни розміру iframe:

http://easyxdm.net/wp/2010/03/17/resize-iframe-based-on-content/

http://kinsey.no/blog/index.php/2010/02/19/resizing-iframes-using-easyxdm/

Easy XDM працює за допомогою PostMessage у сучасних браузерах та базованому на базі Flash рішення як резервний варіант для старих браузерів.

Дивіться також цю тему на Stackoverflow (також є інші, це поширене питання). Крім того , Facebook , здавалося б використовувати аналогічний підхід .

3. Спілкуйтеся через сервер

Іншим варіантом буде надіслати висоту iframe на ваш сервер, а потім опитуватись із цього сервера з батьківської веб-сторінки за допомогою JSONP (або використовувати довге опитування, якщо можливо).


1
Для PostMessage, якщо ви вже використовуєте jQuery, ви також можете поглянути на фантастичний плагін для Ben Alman: benalman.com/projects/jquery-postmessage-plugin
rinogo

8
iFrame-resizer потребує доступу до сервера, на якому розміщено вміст iframe. Тож ви можете використовувати його лише для доменів, якими ви керуєте.
Хокаща

Хороший улов, @Hokascha. Проект претендує на підтримку міждоменних кадрів iframes, але, читаючи документи, показує, що він все ще потребує доступу сервера до вбудованого домену.
StockB

1
Жодна з цих «альтернатив» не є фактичним рішенням цього питання. Автор, що задає запит, хоче встановити висоту iFrame міжфайлових iFrames з веб-сайтів, над якими вони не мають контролю. 1. Потрібен доступ до сервера. 2. Вимагає програмного забезпечення, яке я вважаю поганим. Easy XDM був зроблений, як 10 років тому. Остання версія, починаючи з 2019 року, вимагає спалаху . Спалах, на щастя, мертвий, і ніхто не повинен на нього покладатися. 3. Потрібен доступ до сервера.
redanimalwar

26

Я отримав рішення для встановлення висоти iframe динамічно на основі вмісту. Це працює для міждоменного вмісту. Для досягнення цього необхідно виконати кілька кроків.

  1. Припустимо, ви додали iframe на веб-сторінку "abc.com/page"

    <div> <iframe id="IframeId" src="http://xyz.pqr/contactpage" style="width:100%;" onload="setIframeHeight(this)"></iframe> </div>

  2. Далі вам потрібно прив’язати вікно "message" подія на веб-сторінці "abc.com/page"

window.addEventListener('message', function (event) {
//Here We have to check content of the message event  for safety purpose
//event data contains message sent from page added in iframe as shown in step 3
if (event.data.hasOwnProperty("FrameHeight")) {
        //Set height of the Iframe
        $("#IframeId").css("height", event.data.FrameHeight);        
    }
});

Під час завантаження iframe потрібно надіслати повідомлення вмісту вікна iframe із повідомленням "FrameHeight":

function setIframeHeight(ifrm) {
   var height = ifrm.contentWindow.postMessage("FrameHeight", "*");   
}
  1. На головній сторінці, що додається під iframe тут "xyz.pqr / contactpage", ви повинні прив'язати вікно "message" подія, де всі повідомлення збираються отримувати з батьківського вікна "abc.com/page"
window.addEventListener('message', function (event) {

    // Need to check for safety as we are going to process only our messages
    // So Check whether event with data(which contains any object) contains our message here its "FrameHeight"
   if (event.data == "FrameHeight") {

        //event.source contains parent page window object 
        //which we are going to use to send message back to main page here "abc.com/page"

        //parentSourceWindow = event.source;

        //Calculate the maximum height of the page
        var body = document.body, html = document.documentElement;
        var height = Math.max(body.scrollHeight, body.offsetHeight,
            html.clientHeight, html.scrollHeight, html.offsetHeight);

       // Send height back to parent page "abc.com/page"
        event.source.postMessage({ "FrameHeight": height }, "*");       
    }
});

3
Працює гладко. Дякую купи!
Олексій Леонов

просто це найбільш технічний метод, який я міг би знайти, чудова робота @sudhir, Дякую :)
java acm

14

Що я зробив, порівняв ширину прокрутки iframe, доки вона не змінила розмір, в той час як я поступово встановив висоту IFrame. І це добре спрацювало для мене. Ви можете налаштувати приріст на все, що завгодно.

   <script type="text/javascript">
    function AdjustIFrame(id) {
        var frame = document.getElementById(id);
        var maxW = frame.scrollWidth;
        var minW = maxW;
        var FrameH = 100; //IFrame starting height
        frame.style.height = FrameH + "px"

        while (minW == maxW) {
            FrameH = FrameH + 100; //Increment
            frame.style.height = FrameH + "px";
            minW = frame.scrollWidth;
        }
    }

   </script>


<iframe id="RefFrame" onload="AdjustIFrame('RefFrame');" class="RefFrame"
    src="http://www.YourUrl.com"></iframe>

4
ви, ймовірно, хочете додати обмеження на кількість циклів, інакше значення "while" може перерости у нескінченний цикл.
Кевін Зайферт

1
Це розбиває мою сторінку.
DDDD

Гарне просте рішення. Але в моїх кесах приріст розміру обмежений розміром екрана.
Зета

1

У мене є сценарій, який потрапляє в iframe з його вмістом. Він також переконує, що iFrameResizer існує (він вводить його як сценарій), а потім робить зміну розміру.

Я приведу спрощений приклад нижче.

// /js/embed-iframe-content.js

(function(){
    // Note the id, we need to set this correctly on the script tag responsible for
    // requesting this file.
    var me = document.getElementById('my-iframe-content-loader-script-tag');

    function loadIFrame() {
        var ifrm = document.createElement('iframe');
        ifrm.id = 'my-iframe-identifier';
        ifrm.setAttribute('src', 'http://www.google.com');
        ifrm.style.width = '100%';
        ifrm.style.border = 0;
        // we initially hide the iframe to avoid seeing the iframe resizing
        ifrm.style.opacity = 0;
        ifrm.onload = function () {
            // this will resize our iframe
            iFrameResize({ log: true }, '#my-iframe-identifier');
            // make our iframe visible
            ifrm.style.opacity = 1;
        };

        me.insertAdjacentElement('afterend', ifrm);
    }

    if (!window.iFrameResize) {
        // We first need to ensure we inject the js required to resize our iframe.

        var resizerScriptTag = document.createElement('script');
        resizerScriptTag.type = 'text/javascript';

        // IMPORTANT: insert the script tag before attaching the onload and setting the src.
        me.insertAdjacentElement('afterend', ifrm);

        // IMPORTANT: attach the onload before setting the src.
        resizerScriptTag.onload = loadIFrame;

        // This a CDN resource to get the iFrameResizer code.
        // NOTE: You must have the below "coupled" script hosted by the content that
        // is loaded within the iframe:
        // https://unpkg.com/iframe-resizer@3.5.14/js/iframeResizer.contentWindow.min.js
        resizerScriptTag.src = 'https://unpkg.com/iframe-resizer@3.5.14/js/iframeResizer.min.js';
    } else {
        // Cool, the iFrameResizer exists so we can just load our iframe.
        loadIFrame();
    }    
}())

Тоді вміст iframe можна вводити будь-де в межах іншої сторінки / сайту, використовуючи такий сценарій:

<script
  id="my-iframe-content-loader-script-tag"
  type="text/javascript"
  src="/js/embed-iframe-content.js"
></script>

Вміст iframe буде введено нижче, куди ви розмістите тег сценарію.

Сподіваюся, це комусь корисно. 👍


Добре, я додав <script ... data-src="http://google.com">і заповнив програму iframe src.
BananaAcid

На момент написання, поточна версіяiframe-resizer@4.2.10
BananaAcid

1
... розширено до повного прикладного
коду

@BananaAcid - ваше посилання codeandbox більше не працює
ctrlplusb

дякую, що згадуєте про це, посилання стали: codeandbox.io/s/remote-embed-ifrm-yz0xl . (зверніть увагу: codeandbox "підробляє", використовуючи кілька сторінок і може зависати. Перезавантаження може допомогти)
BananaAcid

1

Ось моє просте рішення на цій сторінці. http://lab.ohshiftlabs.com/iframesize/

Ось як це працює;

введіть тут опис зображення

В основному, якщо ви можете редагувати сторінку в іншому домені, ви можете розмістити іншу сторінку iframe, що належить вашому серверу, яка зберігає висоту для файлів cookie. За допомогою інтервалу зчитування файлів cookie під час оновлення оновіть висоту iframe. Це все.

Завантажити; http://lab.ohshiftlabs.com/iframesize/iframesizepost.zip

Редагування: 2019 грудень

У наведеному вище рішенні в основному використовується інша рамка всередині iframe 3rd iframe належить домену верхньої сторінки, який ви називаєте на цій сторінці рядком запиту, який зберігає значення розміру в cookie, зовнішня сторінка перевіряє цей запит з деяким інтервалом. Але це не гарне рішення, тож слід дотримуватися цього:

На головній сторінці:

window.addEventListener("message", (m)=>{iframeResizingFunction(m)});

Тут ви можете перевірити, m.originзвідки воно походить.

На сторінці кадру:

window.parent.postMessage({ width: 640, height:480 }, "*")

Хоча, будь ласка, не забувайте, що це не так безпечний спосіб. Щоб забезпечити безпечне оновлення * значення (targetOrigin) з потрібним значенням. Дотримуйтесь документації: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage


1
Ці посилання тепер мертві (404), а вміст у відповіді не узагальнено. :(
StockB

1
посилання ще мертві. 404
Арслан Амер

0

Я знайшов інше серверне рішення для веб-розробників за допомогою PHP, щоб отримати розмір iframe.

По-перше, це використання сценарію PHP сервера для зовнішнього виклику за допомогою внутрішньої функції: (наприклад, file_get_contentsз, але curl і dom).

function curl_get_file_contents($url,$proxyActivation=false) {
    global $proxy;
    $c = curl_init();
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7");
    curl_setopt($c, CURLOPT_REFERER, $url);
    curl_setopt($c, CURLOPT_URL, $url);
    curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
    if($proxyActivation) {
        curl_setopt($c, CURLOPT_PROXY, $proxy);
    }
    $contents = curl_exec($c);
    curl_close($c);
    $dom = new DOMDocument();
    $dom->preserveWhiteSpace = false;
    @$dom->loadHTML($contents);
    $form = $dom->getElementsByTagName("body")->item(0);
    if ($contents) //si on a du contenu
        return $dom->saveHTML();
    else
        return FALSE;
}
$url = "http://www.google.com"; //Exernal url test to iframe
<html>
    <head>
    <script type="text/javascript">

    </script>
    <style type="text/css">
    #iframe_reserve {
        width: 560px;
        height: 228px
    }
    </style>
    </head>

    <body>
        <div id="iframe_reserve"><?php echo curl_get_file_contents($url); ?></div>

        <iframe id="myiframe" src="http://www.google.com" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"  style="overflow:none; width:100%; display:none"></iframe>

        <script type="text/javascript">
            window.onload = function(){
            document.getElementById("iframe_reserve").style.display = "block";
            var divHeight = document.getElementById("iframe_reserve").clientHeight;
            document.getElementById("iframe_reserve").style.display = "none";
            document.getElementById("myiframe").style.display = "block";
            document.getElementById("myiframe").style.height = divHeight;
            alert(divHeight);
            };
        </script>
    </body>
</html>

Вам потрібно відобразити під div ( iframe_reserve) html, згенерований викликом функції за допомогою простогоecho curl_get_file_contents("location url iframe","activation proxy")

Після цього функція body body onload за допомогою JavaScript підтримує висоту сторінки iframe просто за допомогою простого керування вмістом div ( iframe_reserve)

Тому я використовував divHeight = document.getElementById("iframe_reserve").clientHeight;для отримання висоти зовнішньої сторінки, яку ми будемо телефонувати після маскування контейнера div ( iframe_reserve). Після цього ми завантажуємо рамку з її гарною висотою.


0

Я зіткнувся з цим питанням, працюючи над чимось на роботі (використовуючи React). В основному ми маємо деякий зовнішній вміст html, який ми зберігаємо в нашій таблиці документів у базі даних, а потім за певних обставин вставляємо на сторінку, коли ти знаходишся у наборі даних Documents.

Отже, з огляду на nрядки, з яких до, nможливо, містив зовнішній html, нам потрібно було розробити систему для автоматичного зміни розміру iframe кожного вбудованого файлу, як тільки вміст повністю завантажиться в кожен. Трохи обертаючи колеса, ось так я це зробив:

  1. Встановіть messageслухача подій в індекс нашого додатку React, який перевіряє наявність конкретного ключа, який ми встановимо від iframe відправника.
  2. У компоненті, який фактично надає iframe, після вставки зовнішнього html до нього додаю <script>тег, який буде чекати window.onloadзапуску iframe . Після запуску ми використовуємо postMessageдля надсилання повідомлення у батьківське вікно з інформацією про ідентифікатор iframe, обчислену висоту тощо.
  3. Якщо початкове збіг відповідає і ключ задоволений у слухачі індексу, захопіть DOM idiframe, який ми передаємо в MessageEventоб'єкті
  4. Як тільки ми маємо iframe, просто встановіть висоту від значення, яке передається від iframe postMessage.
// index
if (window.postMessage) {
    window.addEventListener("message", (messageEvent) => {
        if (
            messageEvent.data.origin &&
            messageEvent.data.origin === "company-name-iframe"
        ) {
            const iframe = document.getElementById(messageEvent.data.id)
            // this is the only way to ensure that the height of the iframe container matches its body height
            iframe.style.height = `${messageEvent.data.height}px`
            // by default, the iframe will not expand to fill the width of its parent
            iframe.style.width = "100%"
            // the iframe should take precedence over all pointer events of its immediate parent
            // (you can still click around the iframe to segue, for example, but all content of the iframe
            // will act like it has been directly inserted into the DOM)
            iframe.style.pointerEvents = "all"
            // by default, iframes have an ugly web-1.0 border
            iframe.style.border = "none"
        }
    })
}
// in component that renders n iframes
<iframe
    id={`${props.id}-iframe`}
    src={(() => {
        const html = [`data:text/html,${encodeURIComponent(props.thirdLineData)}`]
        if (window.parent.postMessage) {
            html.push(
                `
                <script>
                window.onload = function(event) {
                    window.parent.postMessage(
                        {
                            height: document.body.scrollHeight,
                            id: "${props.id}-iframe",
                            origin: "company-name-iframe",
                        },
                        "${window.location.origin}"
                    );
                };
                </script>
                `
            )
        }

        return html.join("\n")
    })()}
    onLoad={(event) => {
        // if the browser does not enforce a cross-origin policy,
        // then just access the height directly instead
        try {
            const { target } = event
            const contentDocument = (
                target.contentDocument ||
                // Earlier versions of IE or IE8+ where !DOCTYPE is not specified
                target.contentWindow.document
            )
            if (contentDocument) {
                target.style.height = `${contentDocument.body.scrollHeight}px`
            }
        } catch (error) {
            const expectedError = (
                `Blocked a frame with origin "${window.location.origin}" ` +
                `from accessing a cross-origin frame.`
            )
            if (error.message !== expectedError) {
                /* eslint-disable no-console */
                console.err(
                    `An error (${error.message}) ocurred while trying to check to see ` +
                    "if the inner iframe is accessible or not depending " +
                    "on the browser cross-origin policy"
                )
            }
        }
    }}
/>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.