วิธีการเข้าถึง Iframe หลักจาก JavaScript


170

ฉันมี IFrame ซึ่งเรียกหน้าโดเมนเดียวกัน ปัญหาของฉันคือฉันต้องการเข้าถึงข้อมูลบางอย่างจาก Iframe แม่จากหน้านี้เรียกว่า (จาก JavaScript) ฉันจะเข้าถึง Iframe นี้ได้อย่างไร

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

แก้ไข: มี iframes ถูกสร้างขึ้นแบบไดนามิก


แม้ว่า iframes จะถูกสร้างขึ้นแบบไดนามิกคุณสามารถกำหนด id ที่ไม่ซ้ำกันใหม่โดยใช้การเรียงลำดับบางอย่างในที่สุดคุณก็ไม่จำเป็นต้องรู้รหัส แต่คุณสามารถค้นหาได้อย่างง่ายดายดูคำตอบของฉัน
Akash Kava

คำตอบ:


138

นอกจากนี้คุณสามารถตั้งชื่อและ ID ให้มีค่าเท่ากัน

<iframe id="frame1" name="frame1" src="any.html"></iframe>

ดังนั้นคุณจะสามารถใช้รหัสถัดไปในหน้าย่อย

parent.document.getElementById(window.name);

16
อาจจะไม่ชัดเจนสำหรับทุกคน แต่ด้วยวิธีนี้คุณสามารถเข้าถึงวัตถุไลบรารีของผู้ปกครอง (เฉพาะในกรณีที่ผู้ปกครองได้โหลดห้องสมุดแล้ว) ตัวอย่าง: เข้าถึง jQuery กับพาเรนต์ $ ('# something')
Zsolti

1
วิธีการแก้ปัญหานี้เข้ากันได้กับโหมด quirks เข้ากันได้ IE5 +
Slayner

แม้ในปี 2559 นี้ใช้งานได้ดีเป็นส่วนหนึ่งของการแก้ปัญหาการพิมพ์เนื้อหาของ IE ที่มีiframeขนาดเล็กเกินไป แต่ทำไมมันถึงใช้งานได้? window.nameส่งคืนสตริง สิ่งที่แตกต่างเกี่ยวกับการใช้งานwindow.nameเพียงแค่ส่งชื่อ id เป็นสตริงที่ใช้ไม่ได้)
Karl

3
สวัสดีมันไม่ทำงานด้วย Chrome 59 .. : VM111: 1 Uncaught DOMException: บล็อกเฟรมที่มีจุดเริ่มต้น " xxx " ไม่ให้เข้าถึงเฟรมข้ามที่มา
Didier68

Chrome เห็นไฟล์ในโฟลเดอร์เดียวกันกับการไขว้กันถ้าไม่ได้ตั้งค่า CORS พวกเขาบอกว่ามันเพื่อความปลอดภัย การตั้งค่า CORS ต้องการเซิร์ฟเวอร์ ให้ข้อความแก่ผู้ใช้เพื่อตั้งค่าเซิร์ฟเวอร์หรือเปลี่ยนเบราว์เซอร์หากตรวจพบ Chrome

90

เพียงโทรwindow.frameElementจากหน้าเว็บที่มีเฟรมของคุณ ถ้าหน้าไม่ได้อยู่ในกรอบแล้วจะframeElementnull

วิธีอื่น (การทำให้องค์ประกอบหน้าต่างภายในเฟรมนั้นมีความสำคัญน้อยกว่า) แต่เพื่อความสมบูรณ์:

/**
 * @param f, iframe or frame element
 * @return Window object inside the given frame
 * @effect will append f to document.body if f not yet part of the DOM
 * @see Window.frameElement
 * @usage myFrame.document = getFramedWindow(myFrame).document;
 */
function getFramedWindow(f)
{
    if(f.parentNode == null)
        f = document.body.appendChild(f);
    var w = (f.contentWindow || f.contentDocument);
    if(w && w.nodeType && w.nodeType==9)
        w = (w.defaultView || w.parentWindow);
    return w;
}

2
ขอบคุณ! ใช้งานได้กับ IE 6+, FF และ Chrome!
rustyx

11
window.frameElementส่งคืนnullเมื่อ window และ iframe มีโดเมนต่างกันเช่นการส่งข้อความข้ามจุด
Qwerty

@Qwerty คุณพบวิธีการแก้ปัญหาใด ๆ ?
Ajay Patidar

@AjayPatidar ฉันคิดว่าฉันยอมแพ้ :(
Qwerty

78

ฉันจะแนะนำให้ใช้postMessage API

ใน iframe ของคุณโทร:

window.parent.postMessage({message: 'Hello world'}, 'http://localhost/');

ในหน้าคุณรวมถึง iframe คุณสามารถฟังเหตุการณ์เช่นนี้:

window.addEventListener('message', function(event) {
      if(event.origin === 'http://localhost/')
      {
        alert('Received message: ' + event.data.message);
      }
      else
      {
        alert('Origin not allowed!');
      }

    }, false);

อย่างไรก็ตามมันเป็นไปได้ที่จะทำการโทรไปยัง windows อื่น ๆ และไม่เพียง iframe

อ่านเพิ่มเติมเกี่ยวกับ postMessage API บนบล็อก John Resigs ที่นี่


7
ฉันคิดว่านี่เป็นคำตอบที่ชัดเจนที่สุด<iframe>เนื้อหาไม่จำเป็นต้องรู้อะไรเลยเกี่ยวกับพ่อแม่และในทางกลับกัน พวกเขาต้องทำตามสัญญาข้อความอย่างง่ายเท่านั้น ! น่ากลัว
mfeineis

1
<iframe> ยังต้องรู้โดเมนของผู้ปกครองใช่ไหม
Homr Zodyssey

1
@HomrZodyssey โดเมนหลักสามารถใช้ได้เป็นกลไกความปลอดภัยเท่านั้นหากไม่รู้จักคุณสามารถตั้งค่า'*'ได้
Amir Ali Akbari

ใช้'*'กับลูกค้า โซลูชันอื่น ๆ ทุกตัวมีข้อผิดพลาดในเบราว์เซอร์ Chrome ที่จัดการไฟล์ในโฟลเดอร์ลูกค้าที่ไม่ใช่ Origin เดียวกันเนื่องจากเซิร์ฟเวอร์ไม่ได้ตั้งค่า นี่คือทางออกที่ดีที่สุดและเดียวเท่านั้น : dyn-web.com/tutorials/iframes/postmessage

30

คำถามเก่า แต่ฉันเพิ่งมีปัญหาเดียวกันนี้และพบวิธีที่จะได้รับ iframe มันเป็นเรื่องของการวนซ้ำผ่านเฟรมของหน้าต่างหลักและทดสอบ contentWindow ของแต่ละเฟรมเทียบกับหน้าต่างที่โค้ดของคุณกำลังทำงานอยู่ ตัวอย่าง:

var arrFrames = parent.document.getElementsByTagName("IFRAME");
for (var i = 0; i < arrFrames.length; i++) {
  if (arrFrames[i].contentWindow === window) alert("yay!");
}

หรือใช้ jQuery:

parent.$("iframe").each(function(iel, el) {
  if(el.contentWindow === window) alert("got it");
});

วิธีนี้จะบันทึกการกำหนด ID ให้กับแต่ละ iframe ซึ่งเป็นสิ่งที่ดีในกรณีของคุณเนื่องจากสร้างขึ้นแบบไดนามิก ฉันหาทางตรงไม่ได้เนื่องจากคุณไม่สามารถรับองค์ประกอบ iframe โดยใช้ window.parent - มันจะตรงไปที่องค์ประกอบหน้าต่างหลัก (ข้าม iframe) ดังนั้นการวนลูปเหล่านั้นจึงเป็นวิธีเดียวเว้นแต่คุณจะต้องการใช้ ID


1
อัปเดต: สิ่งนี้ไม่ได้ตรงตามที่โฆษณาไว้และฉันต้องใช้เอกสาร contentWindow.document === ไม่รู้ว่าทำไม นอกจากนี้ในบางเบราว์เซอร์ฉันใช้ contentDocument ฉันก็ชอบนะ!
Christophe

1
ขอโทษเป็นที่ยอมรับฉันทดสอบเฉพาะใน Firefox :) อย่างไรก็ตามฉันประสบความสำเร็จในการใช้วิธีการ jQuery และ contentWindow ในหลายเบราว์เซอร์
ingredients_15939

1
อัปเดต: ฉันพบว่าคุณยังสามารถใช้ window.frameElement ได้ แต่ฉันไม่แน่ใจว่าเบราว์เซอร์ใดบ้างที่รองรับ
Christophe

2
ฉันไม่คิดว่าสิ่งประเภทนี้จะใช้งานได้อีกต่อไป คุณได้รับข้อผิดพลาดข้ามที่มา
Andrew Mao

@AndrewMao คำถามเกี่ยวกับแหล่งกำเนิดเอกสารเดียวกันดังนั้นจึงไม่มีเหตุผลที่จะได้รับปัญหาข้ามแหล่งที่มา
Christophe

21

คุณสามารถใช้parentเพื่อเข้าถึงหน้าหลัก ดังนั้นในการเข้าถึงฟังก์ชั่นมันจะเป็น:

var obj = parent.getElementById('foo');

1
เควินปัญหาคือรู้รหัส ฉันมีหลาย Iframes และฉันต้องการที่จะเข้าถึงพวกเขาจากภายในรหัส
José Leal

ยังคงได้รับ "บล็อกเฟรมที่มีจุดกำเนิด" other-localhost: 8000 "จากการเข้าถึงเฟรมข้ามจุดกำเนิด"
user2568374

13

เมื่อตั้งค่า id of iframe แล้วคุณสามารถเข้าถึง iframe จากเอกสารภายในดังที่แสดงด้านล่าง

var iframe = parent.document.getElementById(frameElement.id);

ทำงานได้ดีใน IE, Chrome และ FF


ดูเหมือนว่าวิธีการที่ซับซ้อนในการทำvar iframe = frameElement
Oriol

frameElement ส่งคืนวัตถุในบริบทหน้าต่างปัจจุบัน แต่ parent.document.getElementById (frameElement.id) ส่งคืนวัตถุในบริบทหน้าต่างหลักคุณไม่สามารถเรียกใช้ฟังก์ชันจาวาสคริปต์ของหน้าต่างหลักด้วย frameElement ลองใช้ jsfiddle และให้ฉันและตัวอย่างถ้าคุณสามารถ .
Akash Kava

6

อาจจะแค่ใช้

window.parent

เข้าสู่ iframe ของคุณเพื่อรับเฟรม / หน้าต่างการโทร หากคุณมีกรอบการโทรหลายรายการคุณสามารถใช้

window.top

3

ลองสิ่งนี้ในเฟรมหลักของคุณตั้งค่า IFRAME ดังนี้:

<iframe id="frame1" src="inner.html#frame1"></iframe>
<iframe id="frame2" src="inner.html#frame2"></iframe>
<iframe id="frame3" src="inner.html#frame3"></iframe>

โปรดทราบว่ารหัสของแต่ละเฟรมจะถูกส่งเป็นตัวยึดใน src

จากนั้นใน html ภายในของคุณคุณสามารถเข้าถึง id ของเฟรมที่โหลดผ่านทาง location.hash:

<button onclick="alert('I am frame: ' + location.hash.substr(1))">Who Am I?</button>

จากนั้นคุณสามารถเข้าถึง parent.document.getElementById () เพื่อเข้าถึงแท็ก iframe จากภายใน iframe


ใช่นี้จะเป็นทางออกที่ตรรกะมากที่สุด แต่บางครั้งผมต้องเปลี่ยน src ของ iframe .. และผ่านกัญชานี้หรือ GET พารามิเตอร์แต่ละคำขอไม่ดี ..
José Leal

ทำไมการแฮชจึงไม่ผ่านแต่ละครั้ง เบราว์เซอร์สามารถมองเห็นได้เท่านั้นไม่ใช่เซิร์ฟเวอร์และจะไม่ส่งผลต่อการแคชเหมือนรับพารามิเตอร์
Mark Porter

-1
// just in case some one is searching for a solution
function get_parent_frame_dom_element(win)
{
    win = (win || window);
    var parentJQuery = window.parent.jQuery;
    var ifrms = parentJQuery("iframe.upload_iframe");
    for (var i = 0; i < ifrms.length; i++)
    {
        if (ifrms[i].contentDocument === win.document)
            return ifrms[i];
    }
    return null;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.