มีตัวปรับขนาดความสูงของ iframe อัตโนมัติแบบข้ามโดเมนที่ใช้งานได้หรือไม่


111

ฉันลองวิธีแก้ปัญหาเล็กน้อย แต่ไม่ประสบความสำเร็จ ฉันสงสัยว่ามีวิธีแก้ปัญหาหรือไม่โดยเฉพาะอย่างยิ่งกับบทช่วยสอนที่ทำตามได้ง่าย


2
คุณลองแก้ปัญหาอะไรแล้วไม่ประสบความสำเร็จ?
Yzmir Ramirez

1
ฉันลองใช้อันนี้ แต่มันประหลาดในเบราว์เซอร์ webkit ตามที่ระบุไว้ในบทความ: css-tricks.com/cross-domain-iframe-resizingมีอีกอันหนึ่ง แต่ฉันจำ url ไม่ได้
J82


คำตอบ:


69

คุณมีทางเลือกสามทาง:

1. ใช้ iFrame-resizer

นี่คือไลบรารีที่เรียบง่ายสำหรับการรักษาขนาด iFrames ให้เข้ากับเนื้อหา มันใช้ PostMessage และ MutationObserver APIs พร้อมถอยกลับสำหรับ IE8-10 นอกจากนี้ยังมีตัวเลือกสำหรับหน้าเนื้อหาเพื่อขอให้ iFrame มีขนาดที่แน่นอนและยังสามารถปิด iFrame ได้เมื่อคุณทำเสร็จแล้ว

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

2. ใช้ Easy XDM (PostMessage + Flash combo)

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 อยู่แล้วคุณอาจต้องการดูปลั๊กอิน postMessage ที่ยอดเยี่ยมของ Ben Alman: benalman.com/projects/jquery-postmessage-plugin
rinogo

8
iFrame-resizer ต้องการเข้าถึงเซิร์ฟเวอร์ที่โฮสต์เนื้อหา iframe คุณจึงใช้ได้เฉพาะกับโดเมนที่คุณควบคุมเท่านั้น
Hokascha

จับดี @Hokascha. โครงการอ้างว่ารองรับ iframe ข้ามโดเมน แต่การอ่านเอกสารพบว่ายังต้องการการเข้าถึงเซิร์ฟเวอร์ไปยังโดเมนฝังตัว
StockB

1
ไม่มี "ทางเลือก" เหล่านี้เป็นวิธีแก้ปัญหาที่แท้จริงสำหรับปัญหานี้ ผู้ถามต้องการตั้งค่าความสูงของ iFrame ของ iFrames ข้ามโดเมนจากเว็บไซต์ที่พวกเขาไม่สามารถควบคุมได้ 1. ต้องการการเข้าถึงเซิร์ฟเวอร์ 2. ต้องใช้ซอฟต์แวร์ที่ฉันถือว่าไม่ดี Easy XDM ถูกสร้างขึ้นเหมือน 10 ปีที่แล้ว รุ่นล่าสุดจาก 2019 ต้องใช้แฟลช โชคดีที่แฟลชตายแล้วและไม่มีใครควรพึ่งพามัน 3. ต้องการการเข้าถึงเซิร์ฟเวอร์
redanimalwar

28

ฉันมีวิธีแก้ปัญหาในการตั้งค่าความสูงของ iframe แบบไดนามิกตามเนื้อหา สิ่งนี้ใช้ได้กับเนื้อหาข้ามโดเมน มีบางขั้นตอนในการปฏิบัติตามเพื่อให้บรรลุเป้าหมายนี้

  1. สมมติว่าคุณได้เพิ่ม iframe ในหน้าเว็บ "abc.com/page"

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

  2. ถัดไปคุณต้องผูกเหตุการณ์ "ข้อความ" ของ windows ภายใต้หน้าเว็บ "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" คุณต้องผูกเหตุการณ์ "ข้อความ" ของ windows ซึ่งข้อความทั้งหมดจะได้รับจากหน้าต่างหลักของ "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
ทำงานได้อย่างราบรื่น ขอบคุณกอง!
Alex Leonov

นี่เป็นวิธีทางเทคนิคส่วนใหญ่ที่ฉันสามารถหาได้เยี่ยมมาก @sudhir ขอบคุณ :)
java acm

14

สิ่งที่ฉันทำคือเปรียบเทียบ iframe scrollWidth จนกว่าจะเปลี่ยนขนาดในขณะที่ฉันตั้งค่า IFrame Height เพิ่มขึ้น และมันก็ใช้ได้ดีสำหรับฉัน คุณสามารถปรับส่วนเพิ่มตามต้องการได้

   <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' สามารถเสื่อมสภาพเป็นลูปที่ไม่มีที่สิ้นสุด
Kevin Seifert

1
นี่ทำให้หน้าของฉันล่ม
DDDD

วิธีง่ายๆที่ดี แต่ในซีส์ของฉันการเพิ่มขนาดจะถูก จำกัด ไว้โดยขนาดหน้าจอ
Zeta

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

@BananaAcid - ลิงก์โค้ดแซนด์บ็อกซ์ของคุณใช้ไม่ได้อีกต่อไป
ctrlplusb

ขอบคุณสำหรับการกล่าวขวัญว่ามันเชื่อมโยงที่จะกลายเป็น: codesandbox.io/s/remote-embed-ifrm-yz0xl (หมายเหตุ: รหัสแซนด์บ็อกซ์ "ปลอม" โดยใช้หลายหน้าและอาจค้างการโหลดซ้ำอาจช่วยได้)
BananaAcid

1

นี่คือวิธีง่ายๆของฉันที่หน้านี้ http://lab.ohshiftlabs.com/iframesize/

นี่คือวิธีการทำงาน

ป้อนคำอธิบายภาพที่นี่

โดยทั่วไปหากคุณสามารถแก้ไขเพจที่โดเมนอื่นได้คุณสามารถวางเพจ iframe อื่นที่เป็นของเซิร์ฟเวอร์ของคุณซึ่งช่วยประหยัดความสูงให้กับคุกกี้ได้ เมื่อมีการอัปเดตช่วงเวลาอ่านคุกกี้ให้อัปเดตความสูงของ iframe นั้นคือทั้งหมด.

ดาวน์โหลด; http://lab.ohshiftlabs.com/iframesize/iframesizepost.zip

แก้ไข: 2019 ธันวาคม

วิธีแก้ปัญหาข้างต้นโดยทั่วไปจะใช้ iframe อื่นภายใน iframe 3rd iframe ซึ่งเป็นของโดเมนหน้าบนสุดซึ่งคุณเรียกหน้านี้ด้วยสตริงข้อความค้นหาที่บันทึกค่าขนาดลงในคุกกี้หน้านอกจะตรวจสอบข้อความค้นหานี้ด้วยช่วงเวลาบางช่วง แต่ไม่ใช่วิธีแก้ปัญหาที่ดีดังนั้นคุณควรปฏิบัติตามวิธีนี้:

ในหน้าแรก:

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
Arslan Ameer

0

ฉันพบโซลูชันฝั่งเซิร์ฟเวอร์อื่นสำหรับนักพัฒนาเว็บโดยใช้ PHP เพื่อรับขนาดของ iframe

อันดับแรกคือการใช้สคริปต์เซิร์ฟเวอร์ PHP เพื่อโทรภายนอกผ่านฟังก์ชันภายใน: (เช่น a file_get_contentswith แต่ 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 event onload ด้วย javascript จะใช้ความสูงของหน้า iframe เพียงแค่ควบคุม div เนื้อหา ( iframe_reserve)

ดังนั้นฉันใช้divHeight = document.getElementById("iframe_reserve").clientHeight;เพื่อรับความสูงของหน้าภายนอกที่เราจะเรียกหลังจากมาสก์คอนเทนเนอร์ div ( iframe_reserve) หลังจากนี้เราโหลด iframe ด้วยความสูงที่ดีนั่นคือทั้งหมด


0

ฉันพบปัญหานี้ขณะทำงานบางอย่างในที่ทำงาน (โดยใช้ React) โดยทั่วไปเรามีเนื้อหา html ภายนอกที่เราบันทึกลงในตารางเอกสารของเราในฐานข้อมูลจากนั้นแทรกลงในหน้าภายใต้สถานการณ์บางอย่างเมื่อคุณอยู่ในชุดข้อมูลเอกสาร

ดังนั้นเมื่อกำหนดอินไลน์nซึ่งnอาจมี html ภายนอกได้เราจึงจำเป็นต้องคิดค้นระบบเพื่อปรับขนาด iframe ของอินไลน์แต่ละอันโดยอัตโนมัติเมื่อเนื้อหาโหลดเต็มในแต่ละรายการ หลังจากหมุนวงล้อไปสักหน่อยนี่คือวิธีที่ฉันทำมัน:

  1. ตั้งค่าตัวmessageฟังเหตุการณ์ในดัชนีของแอป React ของเราซึ่งตรวจสอบคีย์เฉพาะที่เราจะตั้งค่าจาก iframe ของผู้ส่ง
  2. ในคอมโพเนนต์ที่แสดงผล iframe จริงหลังจากใส่ html ภายนอกเข้าไปแล้วฉันจะต่อท้าย<script>แท็กที่จะรอให้ iframe window.onloadเริ่มทำงาน เมื่อไฟเริ่มทำงานเราจะใช้postMessageเพื่อส่งข้อความไปยังหน้าต่างหลักพร้อมข้อมูลเกี่ยวกับรหัส iframe ความสูงที่คำนวณเป็นต้น
  3. หากจุดเริ่มต้นตรงกันและคีย์เป็นที่พอใจในตัวฟังดัชนีให้คว้า DOM idของ iframe ที่เราส่งผ่านในMessageEventออบเจ็กต์
  4. เมื่อเรามีiframeเพียงแค่ตั้งค่าความสูงจากค่าที่ส่งผ่านจาก postMessageiframe
// 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"
                )
            }
        }
    }}
/>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.