Apakah ada penyesuai otomatis tinggi iframe lintas domain yang berfungsi?

110

Saya mencoba beberapa solusi tetapi tidak berhasil. Saya bertanya-tanya apakah ada solusi di luar sana yang lebih disukai dengan tutorial yang mudah diikuti.

J82
sumber
2
Solusi apa yang Anda coba yang tidak berhasil?
Yzmir Ramirez
1
Saya mencoba yang ini tetapi anehnya di browser webkit seperti yang dinyatakan dalam artikel: css-tricks.com/cross-domain-iframe-resizing Ada satu lagi tetapi saya tidak dapat mengingat url.
J82

Jawaban:

68

Anda memiliki tiga alternatif:

1. Gunakan iFrame-resizer

Ini adalah perpustakaan sederhana untuk menjaga ukuran iFrames sesuai dengan kontennya. Ia menggunakan API PostMessage dan MutationObserver, dengan fallback untuk IE8-10. Ini juga memiliki opsi untuk halaman konten untuk meminta iFrame yang memuatnya berukuran tertentu dan juga dapat menutup iFrame setelah Anda selesai.

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

2. Gunakan Easy XDM (kombinasi PostMessage + Flash)

Easy XDM menggunakan kumpulan trik untuk mengaktifkan komunikasi lintas domain antara jendela yang berbeda di sejumlah browser, dan ada contoh penggunaannya untuk pengubahan ukuran 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 bekerja dengan menggunakan PostMessage di browser modern dan solusi berbasis Flash sebagai fallback untuk browser lama.

Lihat juga utas ini di Stackoverflow (ada juga utas lainnya, ini adalah pertanyaan yang sering ditanyakan). Selain itu, Facebook tampaknya menggunakan pendekatan serupa .

3. Berkomunikasi melalui server

Pilihan lainnya adalah mengirim tinggi iframe ke server Anda dan kemudian melakukan polling dari server tersebut dari halaman web induk dengan JSONP (atau gunakan polling panjang jika memungkinkan).

Janne Aukia
sumber
1
Untuk PostMessage, jika Anda sudah menggunakan jQuery, Anda mungkin juga ingin melihat plugin postMessage Ben Alman yang fantastis: benalman.com/projects/jquery-postmessage-plugin
rinogo
8
iFrame-resizer membutuhkan akses ke server yang menghosting konten iframe. Jadi, Anda hanya dapat menggunakannya untuk domain yang Anda kontrol.
Hokascha
Tangkapan bagus, @Hokascha. Proyek ini mengklaim dukungan untuk iframe lintas domain, tetapi membaca dokumen mengungkapkan bahwa masih memerlukan akses server ke domain tertanam.
StockB
1
Tak satu pun dari "alternatif" ini merupakan solusi aktual untuk masalah ini. Penanya ingin menyetel tinggi iFrame lintas domain iFrame dari situs web yang tidak mereka kendalikan. 1. Membutuhkan akses server. 2. Memerlukan perangkat lunak yang saya anggap buruk. Easy XDM dibuat seperti 10 tahun lalu. Versi terbaru, mulai 2019, membutuhkan flash . Flash, untungnya, mati dan tidak ada yang harus mengandalkannya. 3. Membutuhkan akses server.
redanimalwar
26

Saya mendapat solusi untuk mengatur ketinggian iframe secara dinamis berdasarkan kontennya. Ini berfungsi untuk konten lintas domain. Ada beberapa langkah yang harus diikuti untuk mencapai ini.

  1. Misalkan Anda telah menambahkan iframe di halaman web "abc.com/page"

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

  2. Selanjutnya Anda harus mengikat jendela "pesan" acara di bawah halaman web "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);        
    }
});

Saat memuat iframe, Anda harus mengirim pesan ke konten jendela iframe dengan pesan "FrameHeight":

function setIframeHeight(ifrm) {
   var height = ifrm.contentWindow.postMessage("FrameHeight", "*");   
}
  1. Pada halaman utama yang ditambahkan di bawah iframe di sini "xyz.pqr / halaman kontak" Anda harus mengikat jendela "pesan" acara di mana semua pesan akan diterima dari jendela induk "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 }, "*");       
    }
});
Sudhir
sumber
3
Bekerja dengan mulus. Terima kasih banyak!
Alex Leonov
sederhana ini adalah metode paling teknis yang bisa saya temukan, kerja bagus @sudhir, Terima Kasih :)
java acm
14

Yang saya lakukan adalah membandingkan iframe scrollWidth hingga ukurannya berubah sementara saya secara bertahap menyetel Tinggi IFrame. Dan itu bekerja dengan baik untuk saya. Anda dapat menyesuaikan kenaikan apa pun yang diinginkan.

   <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>
Troy Mitchel
sumber
4
Anda mungkin ingin menambahkan batasan pada jumlah loop, jika tidak, 'while' dapat berubah menjadi loop tak terbatas.
Kevin Seifert
1
Ini merusak halaman saya.
DDDD
Solusi sederhana yang bagus. Namun di masa saya, peningkatan ukuran dibatasi oleh ukuran layar.
Zeta
1

Saya memiliki skrip yang masuk ke iframe dengan isinya. Itu juga memastikan bahwa iFrameResizer ada (menyuntikkannya sebagai skrip) dan kemudian melakukan pengubahan ukuran.

Saya akan memberikan contoh yang disederhanakan di bawah ini.

// /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/[email protected]/js/iframeResizer.contentWindow.min.js
        resizerScriptTag.src = 'https://unpkg.com/[email protected]/js/iframeResizer.min.js';
    } else {
        // Cool, the iFrameResizer exists so we can just load our iframe.
        loadIFrame();
    }    
}())

Kemudian konten iframe dapat disuntikkan di mana saja di halaman / situs lain dengan menggunakan script seperti ini:

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

Konten iframe akan disuntikkan di bawah di mana pun Anda menempatkan tag skrip.

Semoga ini bermanfaat bagi seseorang. 👍

ctrlplusb
sumber
Bagus, saya menambahkan <script ... data-src="http://google.com">dan mengisi src iframe dengannya.
BananaAcid
Saat penulisan, versi saat ini adalah[email protected]
BananaAcid
1
... diperluas ke kode
BananaAcid
@BananaAcid - tautan kode dan kotak Anda tidak lagi berfungsi
ctrlplusb
terima kasih telah menyebutkannya, tautan menjadi: codesandbox.io/s/remote-embed-ifrm-yz0xl . (catatan: kode dan kotak "palsu" menggunakan beberapa halaman dan mungkin
macet
1

Inilah solusi sederhana saya di halaman ini. http://lab.ohshiftlabs.com/iframesize/

Inilah cara kerjanya;

masukkan deskripsi gambar di sini

Pada dasarnya jika Anda dapat mengedit halaman di domain lain, Anda dapat menempatkan halaman iframe lain milik server Anda yang menyimpan tinggi untuk cookie. Dengan cookie baca interval saat diperbarui, perbarui tinggi iframe. Itu semuanya.

Unduh; http://lab.ohshiftlabs.com/iframesize/iframesizepost.zip

Edit: 2019 Desember

Solusi di atas pada dasarnya menggunakan iframe lain di dalam iframe 3rd iframe milik domain halaman atas, yang Anda sebut halaman ini dengan string kueri yang menyimpan nilai ukuran ke cookie, halaman luar memeriksa kueri ini dengan beberapa interval. Tetapi ini bukan solusi yang baik jadi Anda harus mengikuti yang ini:

Di halaman atas:

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

Di sini Anda dapat memeriksa m.originuntuk melihat dari mana asalnya.

Di halaman bingkai:

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

Meskipun, tolong jangan lupa ini bukan cara yang aman. Untuk membuatnya aman perbarui * nilai (targetOrigin) dengan nilai yang Anda inginkan. Ikuti dokumentasi: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

siniradam
sumber
1
Tautan ini sekarang sudah mati (404) dan isinya tidak diringkas dalam jawaban. :(
StockB
1
link masih mati. 404
Arslan Ameer
0

Saya menemukan solusi sisi server lain untuk web dev menggunakan PHP untuk mendapatkan ukuran iframe.

Pertama adalah menggunakan skrip server PHP ke panggilan eksternal melalui fungsi internal: (seperti file file_get_contents dengan tetapi curl dan 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>

Anda perlu menampilkan di bawah div ( iframe_reserve) html yang dihasilkan oleh pemanggilan fungsi dengan menggunakan simpleecho curl_get_file_contents("location url iframe","activation proxy")

Setelah melakukan ini, fungsi acara tubuh onload dengan javascript mengambil ketinggian halaman iframe hanya dengan kontrol sederhana dari div konten (iframe_reserve )

Jadi saya biasa divHeight = document.getElementById("iframe_reserve").clientHeight;mendapatkan tinggi halaman eksternal yang akan kita panggil setelah menutupi div container ( iframe_reserve). Setelah ini kami memuat iframe dengan ketinggian yang bagus itu saja.

headmax
sumber
0

Saya mengalami masalah ini saat mengerjakan sesuatu di tempat kerja (menggunakan React). Pada dasarnya, kami memiliki beberapa konten html eksternal yang kami simpan ke dalam tabel dokumen kami di database dan kemudian dimasukkan ke halaman dalam keadaan tertentu saat Anda berada di kumpulan data Dokumen.

Jadi, mengingat nsebaris, yang hingga ndapat berisi html eksternal, kami perlu merancang sistem untuk secara otomatis mengubah ukuran iframe dari setiap sebaris setelah konten dimuat sepenuhnya di masing-masing. Setelah memutar roda saya sebentar, beginilah akhirnya saya melakukannya:

  1. Atur messageevent listener di indeks aplikasi React kami yang memeriksa kunci spesifik yang akan kami atur dari iframe pengirim.
  2. Di komponen yang benar-benar membuat iframe, setelah memasukkan html eksternal ke dalamnya, saya menambahkan <script>tag yang akan menunggu iframe window.onloaddiaktifkan. Setelah itu diaktifkan, kami menggunakan postMessageuntuk mengirim pesan ke jendela induk dengan informasi tentang id iframe, tinggi yang dihitung, dll.
  3. Jika asal cocok dan kuncinya terpenuhi di pendengar indeks, ambil DOM iddari iframe yang kita teruskan di MessageEventobjek
  4. Setelah kami memiliki iframe, cukup atur tinggi dari nilai yang diteruskan dari 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"
                )
            }
        }
    }}
/>
John Duncan
sumber