การเรียกใช้ฟังก์ชันหน้าต่างพาเรนต์จาก iframe


282

ฉันต้องการเรียกใช้ฟังก์ชัน JavaScript หน้าต่างหลักจาก iframe

<script>
    function abc()
    {
        alert("sss");
    }
</script>

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>

1
ฉันไม่สามารถแสดงอะไรได้เลยในตอนนี้ (2559) ฉันไม่รู้ว่าคนที่แก่กว่าจะสนับสนุนหรือไม่
Weijing Jay Lin

คำตอบ:


438
<a onclick="parent.abc();" href="#" >Call Me </a>

ดูwindow.parent

ส่งคืนการอ้างอิงถึงพาเรนต์ของหน้าต่างปัจจุบันหรือเฟรมย่อย

หากหน้าต่างไม่มีพาเรนต์คุณสมบัติพาเรนต์จะเป็นการอ้างอิงถึงตัวเอง

เมื่อหน้าต่างมีการโหลดใน<iframe>, <object>หรือ<frame>พ่อแม่ของมันคือหน้าต่างที่มีองค์ประกอบฝังหน้าต่าง


17
คำนึงถึงว่าเอกสารหลักและเอกสาร iframe ต้องตรงกันโดยโปรโตคอลและชื่อโดเมน หากไม่เกิดขึ้นคุณจะได้รับข้อผิดพลาดด้านความปลอดภัยเนื่องจากไม่อนุญาตให้มีการเขียนสคริปต์ข้ามโดเมน
a4bike

M เพียงแค่สงสัยว่าคนใดคนหนึ่งที่ทั้งสองalertจะถูกเรียก; alertฟังก์ชั่นของผู้ปกครองหรือฟังก์ชั่น iframe alertในกรณีที่parent.abc();เรียกว่าบน iframe?
Prakhar Mishra

@ PrakharMishra อย่าสับสน parent หมายถึง parent
Sahu V Kumar

3
@ a4bike สำหรับสถานการณ์ดังกล่าวwindow.postMessage()(หรือwindow.parent.postMessage()) อยู่ ตรวจสอบ@Andrii คำตอบ
Fr0zenFyr

81

เมื่อเร็ว ๆ นี้ฉันต้องค้นหาสาเหตุที่ไม่ทำงานเช่นกัน

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

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="parent.abc();" href="#">Click Me</a>
    </iframe>
</body>

หวังว่านี่จะช่วยให้ทุกคนที่สะดุดกับปัญหานี้อีกครั้ง


1
ไม่มีเทคนิคใด ๆ ที่กล่าวถึงในโพสต์นี้ทำงานบน Chrome คำตอบสำหรับเรื่องนี้?
Kumar Kush

3
หากฉันจำได้อย่างถูกต้องฉันจะไม่สามารถใช้งานได้ตามปกติหาก iframe มีโดเมนที่แตกต่างจากผู้ปกครอง ขออภัยนี่ไม่ใช่วิธีแก้ปัญหา แต่อาจอธิบายได้ว่าทำไมมันไม่ทำงาน
แอชคลาร์ก

1
ใช่. ฉันรู้ว่าเป็นเพราะโดเมนที่ต่างกัน แต่ไม่มีวิธีแก้ไขปัญหานี้หรือไม่
Kumar Kush

1
ฉันเพิ่งโพสต์สิ่งที่อาจเป็นวิธีแก้ปัญหาของคุณ ลองดูคำตอบอื่น ๆ
Ash Clarke

1
ตามกฎการกำหนดนโยบายต้นกำเนิดเดียวกัน (ดู: en.wikipedia.org/wiki/… ) โดเมนย่อยจะถือเป็นชื่อโฮสต์ที่แตกต่างกันไปยังโดเมนย่อยของโดเมน หากคุณยังไม่ได้ลองตั้งค่า document.domain เป็นโดเมนย่อย?
Ash Clarke

73

Window.postMessage ()

วิธีนี้ช่วยให้สามารถcross-originสื่อสารได้อย่างปลอดภัย

และถ้าคุณมีการเข้าถึงรหัสหน้าพ่อแม่ผู้ปกครองแล้ววิธีใดสามารถเรียกได้ว่าเป็นข้อมูลใด ๆ Iframeที่สามารถส่งโดยตรงจาก นี่คือตัวอย่างเล็ก ๆ :

เพจระดับบน:

if (window.addEventListener) {
    window.addEventListener("message", onMessage, false);        
} 
else if (window.attachEvent) {
    window.attachEvent("onmessage", onMessage, false);
}

function onMessage(event) {
    // Check sender origin to be trusted
    if (event.origin !== "http://example.com") return;

    var data = event.data;

    if (typeof(window[data.func]) == "function") {
        window[data.func].call(null, data.message);
    }
}

// Function to be called from iframe
function parentFunc(message) {
    alert(message);
}

รหัส iframe:

window.parent.postMessage({
    'func': 'parentFunc',
    'message': 'Message text from iframe.'
}, "*");
// Use target origin instead of *

ปรับปรุง:

หมายเหตุด้านความปลอดภัย:

ระบุเป้าหมายเฉพาะเสมอไม่ใช่*ถ้าคุณทราบว่าควรจะวางเอกสารของหน้าต่างอื่นไว้ที่ใด ล้มเหลวในการให้เป้าหมายที่เฉพาะเจาะจงเปิดเผยข้อมูลที่คุณส่งไปยังเว็บไซต์ที่เป็นอันตรายที่สนใจ (ความเห็นโดยZalemCitizen )

อ้างอิง:


1
ฉันชอบที่จะใช้สิ่งนี้มากกว่าคนอื่น ๆ โดยเฉพาะอย่างยิ่งเนื่องจากเหมาะสมกว่าที่จะใช้ iframes บนเอกสารต้นฉบับข้าม (แม้ว่าโปรแกรมเมอร์จะใช้ประโยชน์จาก iframes บ่อยกว่าไม่) และได้รับการสนับสนุนอย่างกว้างขวางสำหรับฟังก์ชันนี้ในเบราว์เซอร์
Fr0zenFyr

1
ขอบคุณ! ฉันจะต้องใช้เวลาหนึ่งชั่วโมงหรือมากกว่านั้นในการย้อนกลับและค้นคว้าวิธีการส่งข้อความด้วยตัวอย่างที่ซับซ้อนและละเอียด สิ่งนี้ใช้ได้ใน 60 วินาที ขอบคุณสำหรับตัวอย่างที่กระชับและตรงประเด็น
Randall ถึง

2
ควรยกระดับนั้น (จากเอกสารเว็บ MDN ): ระบุเป้าหมายเฉพาะเจาะจงเสมอไม่ใช่ * หากคุณทราบว่าควรจะวางเอกสารของหน้าต่างอื่นที่ใด ล้มเหลวในการให้เป้าหมายที่เฉพาะเจาะจงเปิดเผยข้อมูลที่คุณส่งไปยังเว็บไซต์ที่เป็นอันตรายที่สนใจ
ZalemCitizen

20

ฉันโพสต์สิ่งนี้เป็นคำตอบแยกต่างหากเนื่องจากไม่เกี่ยวข้องกับคำตอบที่ฉันมีอยู่

ปัญหานี้ถูกครอบตัดอีกครั้งเมื่อเร็ว ๆ นี้เพื่อเข้าถึงผู้ปกครองจาก iframe ที่อ้างอิงโดเมนย่อยและการแก้ไขที่มีอยู่ไม่ทำงาน

เวลานี้คำตอบคือการแก้ไข document.domain ของเพจระดับบนและ iframe ให้เหมือนกัน สิ่งนี้จะหลอกการตรวจสอบนโยบายต้นกำเนิดเดียวกันว่าพวกเขาอยู่ร่วมกันในโดเมนเดียวกัน (โดเมนย่อยถูกพิจารณาว่าเป็นโฮสต์ที่แตกต่างกันและล้มเหลวในการตรวจสอบนโยบายต้นกำเนิดเดียวกัน)

แทรกรายการต่อไปนี้<head>ของหน้าใน iframe เพื่อให้ตรงกับโดเมนหลัก (ปรับสำหรับประเภทเอกสารของคุณ)

<script>
    document.domain = "mydomain.com";
</script>

โปรดทราบว่าการทำเช่นนี้จะทำให้เกิดข้อผิดพลาดในการพัฒนา localhost ดังนั้นให้ตรวจสอบดังต่อไปนี้เพื่อหลีกเลี่ยงข้อผิดพลาด:

if (!window.location.href.match(/localhost/gi)) {
    document.domain = "mydomain.com";
} 

และสิ่งที่เกี่ยวกับการทดสอบใน localhost? มีวิธีแก้ปัญหาสำหรับอะไร
Umesh Awasthi

โปรดดู: "โปรดทราบว่าสิ่งนี้จะทำให้เกิดข้อผิดพลาดในการพัฒนา localhost ดังนั้นโปรดใช้เครื่องหมายตรวจสอบต่อไปนี้เพื่อหลีกเลี่ยงข้อผิดพลาด"
Ash Clarke

2
เป็นที่น่าสังเกตว่า (อย่างน้อยใน Google Chrome) ทั้งผู้ปกครองและเด็กต้องตั้งค่า document.domain แม้ว่าหนึ่งในนั้นจะถูก "แก้ไข"! ตัวอย่าง: Parent คือexample.comiframe abc.example.comดังนั้นทั้ง parent และ iframe ต้องเรียกdocument.domain = "example.com"
KillerX

ใช่ถูกต้องฉันพิมพ์ผิดที่นี่: "หน้าใน iframe ให้เหมือนกัน" ควรเป็น "หน้าและ iframe ให้เหมือนกัน" ..... ขอบคุณ!
Ash Clarke

สำหรับ if () ทำไมคุณไม่ใช้เพียงแค่ถ้า (document.domain! = "mydomain.com" นอกจากนี้ฉันสับสน <script> ไปที่หน้าต่างหลักหรือ iFrame หรือไม่ด้วยการตั้งค่า document.domain ใน iFrame สร้าง "ไม่สามารถตั้งค่าคุณสมบัติ 'domain' ใน 'Document': 'localhost' ไม่ใช่ส่วนต่อท้ายของ 'sc-localhost'
2568374

18

คุณสามารถใช้ได้

window.top

ดูต่อไปนี้

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="window.top.abc();" href="#">Click Me</a>
    </iframe>
</body>

เมื่อพยายามโทร parent.custom_function (); จาก iframe ไม่สามารถใช้งานได้คุณอาจพบ window.top.custom_function (); จะทำงาน. ทำงานให้ฉันด้วยเหตุผลแปลก ๆ จาวาสคริปต์ของฉันในหน้าต่างหลักทั้งหมดฝังอยู่ในส่วนท้ายฉันอ่านบางที่รวมถึงไฟล์จาวาสคริปต์ในส่วนท้ายทำให้เกิดปัญหา parent.custom_function () ไม่ทำงาน
Friso Horstman

@Vinothkumar หนึ่งคำถามกรุณาซึ่งเป็นความแตกต่างระหว่างเรียก "window.top.abc ()" กว่าโทรเท่านั้น "abc ()" ขอบคุณล่วงหน้า =)
Zilev av

@Zilev av จุดทั้งหมดของเธรดนี้กำลังเรียกใช้ฟังก์ชันในเอกสารพาเรนต์จาก child iframe นั่นคือความแตกต่าง การโทรabc()จะใช้ได้ก็ต่อเมื่อfunction abc()มีการประกาศใน iframeซึ่งตรงข้ามกับในหน้าหลัก window.top.abc()แยกออกจาก iframe ลงในเอกสารหลัก
Sean Kendle

3

นอกจากนี้สำหรับผู้ที่ต้องการมันอีก วิธีแก้ปัญหาของ Ash Clarke ไม่ทำงานหากใช้โปรโตคอลที่แตกต่างกันดังนั้นให้แน่ใจว่าหากคุณใช้ SSL อยู่ iframe ของคุณก็กำลังใช้ SSL อยู่เช่นกันหรือจะทำให้ฟังก์ชั่นหยุดทำงาน วิธีแก้ปัญหาของเขาใช้งานได้กับโดเมนเองดังนั้นขอบคุณสำหรับสิ่งนั้น


2

โซลูชันที่ Ash Clarke มอบให้กับโดเมนย่อยนั้นใช้งานได้ดี แต่โปรดทราบว่าคุณต้องรวม document.domain = "mydomain.com"; ทั้งในส่วนหัวของหน้า iframe และส่วนหัวของหน้าหลักตามที่ระบุในลิงก์การตรวจสอบนโยบายต้นทางเดียวกัน

ส่วนขยายที่สำคัญสำหรับนโยบายกำเนิดเดียวกันนี้นำมาใช้สำหรับการเข้าถึง JavaScript DOM (แต่ไม่ใช่สำหรับรสชาติอื่น ๆ ส่วนใหญ่ของการตรวจสอบที่มาเดิม) คือเว็บไซต์สองแห่งที่แชร์โดเมนระดับบนสุดทั่วไปอาจเลือกที่จะสื่อสารแม้จะล้มเหลว "โฮสต์เดียวกัน" ตรวจสอบโดยการตั้งค่าคุณสมบัติ document.domain DOM ที่เกี่ยวข้องไปเป็นแฟรกเมนต์ขวามือเดียวกันของชื่อโฮสต์ปัจจุบัน ตัวอย่างเช่นถ้า http://en.example.com/และhttp://fr.example.com/ทั้งคู่ตั้ง document.domain เป็น "example.com" ทั้งคู่จะมาจากจุดนั้นบนจุดเริ่มต้นเดียวกันซึ่งถือว่าเป็นจุดกำเนิดเดียวกันสำหรับ วัตถุประสงค์ของการจัดการ DOM


ใช่ถูกต้องฉันพิมพ์ผิดที่นี่: "หน้าใน iframe ให้เหมือนกัน" ควรเป็น "หน้าและ iframe ให้เหมือนกัน" ..... ขอบคุณ!
Ash Clarke

วิธีการเกี่ยวกับการใช้ไฟล์ในเครื่องคอมพิวเตอร์? คุณค่าของdocument.domainคืออะไร?
Raptor

มันจะเป็นlocalhostหรือที่อยู่ IP ของเครื่อง (โดยทั่วไป127.0.0.1) ขึ้นอยู่กับสิ่งที่อยู่ในแถบที่อยู่ URL
Ash Clarke

2

parent.abc ()จะทำงานในโดเมนเดียวกันเท่านั้นเนื่องจากวัตถุประสงค์ด้านความปลอดภัย ฉันลองวิธีแก้ปัญหานี้และฉันทำงานได้อย่างสมบูรณ์

<head>
    <script>
    function abc() {
        alert("sss");
    }

    // window of the iframe
    var innerWindow = document.getElementById('myFrame').contentWindow;
    innerWindow.abc= abc;

    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="abc();" href="#">Click Me</a>
    </iframe>
</body>

หวังว่านี่จะช่วยได้ :)


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

1

ด้วย Firefox และ Chrome คุณสามารถใช้:

<a href="whatever" target="_parent" onclick="myfunction()">

หากฟังก์ชันของฉันมีทั้งใน iframe และในพาเรนต์จะเรียกว่าพาเรนต์หนึ่ง


มันไม่ทำงาน นี่คือตัวอย่างของฉัน: dotku.github.io/tech/html/iframe/iframe_function_container.html
Weijing Jay Lin

ตามที่ระบุไว้โดย Ash Clarke จาวาสคริปต์ที่คุณต้องการโทรจาก child iframe จะต้องอยู่ในหัวของผู้ปกครอง
เกล็ดหิมะ

คำตอบที่ยอมรับไม่จำเป็นต้องสคริปต์อยู่ในหัว ฉันไม่ได้ทดสอบว่าโซลูชันนี้ยังไม่ต้องการให้สคริปต์อยู่ในหัวหรือไม่
Guy Schalnat

0

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

เพื่อหลีกเลี่ยงปัญหานี้ให้ใช้รูปแบบโมดูล ในหน้าต่างหลัก:

var myThing = {
    var i = 0;
    myFunction : function () {
        // do something
    }
};

var newThing = Object.create(myThing);

จากนั้นใน iframe:

function myIframeFunction () {
    parent.myThing.myFunction();
    alert(parent.myThing.i);
};

สิ่งนี้คล้ายกับรูปแบบที่อธิบายไว้ในบทมรดกของข้อความน้ำเชื้อของ Crockford "Javascript: The Good Parts" คุณสามารถเรียนรู้เพิ่มเติมได้ที่หน้า w3 สำหรับแนวทางปฏิบัติที่ดีที่สุดของ Javascript https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.