부모 페이지에서 iframe으로 JavaScript 코드 호출


615

기본적으로, 나는 한 iframe페이지에 포함하고는 iframe몇 가지가 자바 스크립트 내가 부모 페이지에서 호출 할 필요가 루틴을.

이제는 전화해야하기 때문에 그 반대가 매우 간단 parent.functionName()하지만 불행히도 나는 그 반대가 필요합니다.

내 문제는의 소스 URL 을 변경하는 것이 아니라에 iframe정의 된 함수를 호출하는 것 iframe입니다.


42
parent.fuctioName ()에 대한 메모는 iframe의 부모 html에서 함수를 호출하는 문제를 해결했습니다. 고맙습니다!
— CyberFonic 2016 년

1
디버깅 할 때 찾고있는 iframe에 대한 참조가 있는지 확인하려는 경우 window.location.href 또는 parent.location.href와 같은 작업을 수행하여 iframe의 URL을 볼 수 있습니다.
— AaronLS

@le dorfier의 답변을 참조하십시오 ... 완벽하게 작동했습니다.
— ErickBest

답변:


542

iFrame의 ID가 "targetFrame"이고 호출하려는 함수가 다음과 같다고 가정하십시오 targetFunction().

document.getElementById('targetFrame').contentWindow.targetFunction();

window.frames대신을 사용하여 프레임에 액세스 할 수도 있습니다 document.getElementById.

// this option does not work in most of latest versions of chrome and Firefox
window.frames[0].frameElement.contentWindow.targetFunction(); 

3
FF 7, Chrome 12, IE 8/9 및 Safari에서 작동 (이 버전은 확실하지 않음)
— Darcy

3
이 솔루션은 내 가제트에서 작동하지 않습니다. 여기 코드 document.getElementById('remote_iframe_0').contentWindow.my.create_element_gadg‌​et('verify_user');"는 apache shindig 서버에 의해 프로그래밍 방식으로 생성되었지만 window.parent.document.getElementById('remote_iframe_0').contentWindow.my.create_element_gadg‌​et('verify_user');"작동합니다.
— J Bourne

3
@Dirty Henry "jQuery 함수"는 무엇을 의미합니까? jQuery는 JavaScript 라이브러리입니다.
— Joel Anair

8
@JellicleCat 그것은 부모 페이지와 iframe이 서로 다른 호스트를 가지고 있기 때문에 메시지가 알려주는 것처럼 교차 출처 프레임을 만들기 때문입니다. 부모 페이지와 iframe의 프로토콜, 도메인 및 포트가 일치하는 한 모든 것이 잘 작동합니다.
— Mark Amery

1
언급 한 window.frames 메서드를 사용하는 방법에 대한 예를 추가했습니다.
— Elijah Lynn

145

여기서 알아야 할 몇 가지 단점이 있습니다.

  1. HTMLIFrameElement.contentWindow아마도 더 쉬운 방법 일지 모르지만 표준 속성은 아니며 일부 브라우저는 대부분 오래된 브라우저를 지원하지 않습니다. DOM Level 1 HTML 표준은 window객체 에 대해 아무 말도하지 않기 때문 입니다.

  2. HTMLIFrameElement.contentDocument.defaultView몇 가지 구형 브라우저는 허용하지만 IE는 허용하지 않는을 시도 할 수도 있습니다 . 그럼에도 불구하고 표준은 window(1)과 같은 이유로 객체를 다시 가져 왔다고 명시 적으로 말하지 않지만, 관심이 있다면 여기에서 몇 가지 추가 브라우저 버전을 선택할 수 있습니다.

  3. window.frames['name']창을 반환하는 것이 가장 오래되고 가장 안정적인 인터페이스입니다. 그러나 name="..."이름으로 프레임을 얻을 수 있으려면 속성 을 사용해야합니다 . 이는 약간 추한 / 더 이상 사용되지 않거나 / 전환 된 것입니다. ( id="..."더 좋을 것이지만 IE는 그것을 좋아하지 않습니다.)

  4. window.frames[number]또한 매우 신뢰할 만하지 만 올바른 색인을 아는 것이 속임수입니다. 예를 들어이 문제를 해결할 수 있습니다. 페이지에 iframe이 하나만 있다는 것을 알고 있다면

  5. 자식 iframe이 아직로드되지 않았거나 액세스 할 수 없도록 잘못되었습니다. 통신 흐름을 반대로하는 것이 더 쉽다는 것을 알게 될 것입니다. 즉, 아이 iframe window.parent이로드가 완료되고 다시 호출 될 준비가되면 스크립트에 알리도록합니다 . 자체 객체 중 하나 (예 : 콜백 함수)를 상위 스크립트에 전달하면 해당 상위는 연관된 HTMLIFrameElement에 대해 걱정할 필요없이 iframe의 스크립트와 직접 통신 할 수 있습니다.


13
좋은 물건! 특히 귀하의 제안 5.은 매우 귀중한 것으로 나타났습니다. Chrome의 부모에서 iFrame 기능에 액세스하려고 할 때 많은 골치 아픈 문제를 해결했습니다. iFrame에서 함수 객체를 전달하면 Chrome, FF 및 심지어 IE에서 9에서 7까지의 매력처럼 실행되었으며 함수가 이미로드되었는지 쉽게 확인할 수 있습니다. 감사!
— Jpsy

3 번은 효과가 있지만 @le dorfier가 자신의 의견에 넣는 것처럼하는 것이 좋습니다. 그 methode()부분을 주목하십시오 .
— ErickBest

또한 최신 브라우저 (FF29 및 Chrome34에서 테스트)의 보안 제한으로 인해 함수 호출 위치가 중요합니다. 스크립트 태그 또는 $ (document) .ready ()에서 함수를 호출하면 작동하지 않습니다. 대신 본문의 onload 태그 또는 다른 곳에서 제안 된대로 앵커 <a href="javascript:doit();">이를 수행 </a>하십시오 ( stackoverflow.com/questions/921387/… 참조 ). 콜백으로 스크립트에 함수 호출을 전달하는 것도 일반적으로 작동합니다.
— titusn

@ chovy : 아니오, 이것에 대한 Vivek의 대답을 명확히하십시오.
— bobince

66

에서 부모 JS 함수를 호출 할 iframe수 있지만 부모와 페이지에로드 된 페이지가 모두 iframe같은 도메인 (예 : abc.com)에서 온 경우와 둘 다 동일한 프로토콜을 사용하는 경우에만 둘 다 on http://또는 https://입니다.

아래 언급 된 경우 통화가 실패합니다.

  1. 부모 페이지와 iframe 페이지는 다른 도메인에 있습니다.
  2. 그들은 다른 프로토콜을 사용하고 있습니다. 하나는 http : //에 있고 다른 하나는 https : //에 있습니다.

이 제한에 대한 해결 방법은 매우 안전하지 않습니다.

예를 들어 도메인 superwinningcontest.com을 등록하고 사람들의 이메일에 대한 링크를 보냈다고 상상해보십시오. 그들이 메인 페이지를로드 할 때 iframe거기에 몇 가지를 숨기고 Facebook 피드를 읽거나 최근 Amazon 또는 PayPal 거래를 확인하거나 충분한 보안을 구현하지 않은 서비스를 사용하는 경우 돈을 송금 할 수 있습니다 계정. 이것이 JavaScript가 동일한 도메인 및 동일한 프로토콜로 제한되는 이유입니다.


6
해결 방법은 아름답고 위험한 en.wikipedia.org/wiki/Cross-document_messaging
— Laramie

다른 하위 도메인으로 인해 이것이 실패하는지 아는 사람이 있습니까? iframe이 부모 창 함수를 호출하지만 호출이 발생하지 않는다고 생각하는 문제를 디버깅하는 데 어려움이 있습니다.
— Jake

1
포트 번호가 다르면 실패합니다. 즉 abc.com:80! = abc.com:8080
— prasanthv

31

IFRAME에서 함수를 창 객체에 공개하십시오.

window.myFunction = function(args) {
   doStuff();
}

부모 페이지에서 액세스하려면 다음을 사용하십시오.

var iframe = document.getElementById("iframeId");
iframe.contentWindow.myFunction(args);

좋은 답변입니다. 컨벤션이 확실하지 않습니다. 후속 질문이 있습니다. 새로운 질문을 시작해야한다면 그렇게 할 것입니다. 하나의 문제가 있습니다. 내 페이지의 iframe이 동적으로 채워집니다. onclick()이벤트가 단순히 호출 하는 버튼이 포함되어 있습니다 window.print(). 이것은 내용 을 iframe완벽하게 인쇄합니다 . 그러나 iframe의 페이지의 공개 함수가 호출 window.print()되고 상위 페이지가 공개 함수를 호출하면 상위의 컨텐츠가 인쇄됩니다. window.print()공개 함수에서 호출 이 onclick이벤트 에서와 같이 작동 하도록 어떻게 코딩해야 합니까?
— Karl

1
@Karl 전화하고 싶지 않습니다 onclick. 에 전화하고 싶습니다 iframe.contentWindow.print().
— Tomalak

불행히도, 그것은 작동하지 않습니다. 새 질문을 시작하고 코드를 문서화해야합니까? 어느 쪽이든 부모 페이지 내용도 인쇄됩니다. document.getElementById('myFrame').contentWindow.print();' and the pubic function 호출하는 printContent ()`(oncick 이벤트 핸들러가 아님)는 다음과 같이 호출 window.print()되었습니다.document.getElementById('myFrame').contentWindow.printContent();
— Karl

1
@Karl-예, 새로운 질문을 시작하는 것이 가장 좋습니다. 부모 윈도우가 iframe과 다른 도메인에 있지 않는 한. 그런 다음 아무 것도 시도하지 않습니다 .
— Tomalak

내가보고 한 것은 IE 문제 (IE8에서 테스트) 인 것 같습니다. 현재 Chrome 버전에는 문제가 없습니다. 그러나 다른 브라우저는 아직 테스트하지 않았습니다. 관심있는 사람들은이 jsFiddle을 참조하십시오 (동적 iframe을로드하고 부모로부터 공개 함수를 호출하는 좋은 예라고 생각합니다)
— Karl

20

iFrame의 대상과 포함하는 문서가 다른 도메인에있는 경우 이전에 게시 된 방법이 작동하지 않을 수 있지만 해결 방법이 있습니다.

예를 들어, 문서 A에 문서 B가 포함 된 iframe 요소가 있고 문서 A의 스크립트가 문서 B의 Window 객체에서 postMessage ()를 호출하면 해당 객체에서 메시지 이벤트가 시작되고 문서 A의 스크립트는 다음과 같습니다.

var o = document.getElementsByTagName('iframe')[0];
o.contentWindow.postMessage('Hello world', 'http://b.example.org/');

들어오는 이벤트에 대한 이벤트 핸들러를 등록하기 위해 스크립트는 addEventListener () (또는 유사한 메커니즘)를 사용합니다. 예를 들어, 문서 B의 스크립트는 다음과 같습니다.

window.addEventListener('message', receiver, false);
function receiver(e) {
  if (e.origin == 'http://example.com') {
    if (e.data == 'Hello world') {
      e.source.postMessage('Hello', e.origin);
    } else {
      alert(e.data);
    }
  }
}

이 스크립트는 먼저 도메인이 예상 도메인인지 확인한 다음 사용자에게 표시하거나 메시지를 보낸 문서로 메시지를 다시 보내 메시지에 응답하는 메시지를 확인합니다.

http://dev.w3.org/html5/postmsg/#web-messaging을 통해


1
easyXDM 은 구형 브라우저 (고집 공룡의 플래시 (LocalConnection) 대체)를 포함하여 이전 브라우저의 PostMessage에 대한 추상화를 제공합니다.
— JonnyReeves

1
훌륭합니다 ... 위의 답변을 시도한 후에 마침내 답변을 얻었습니다. 감사합니다!
— vkGunasekaran

9

기록을 위해 오늘도 같은 문제가 발생했지만 이번에는 페이지가 iframe이 아닌 객체에 포함되었습니다 (XHTML 1.1 문서이므로). 객체와 작동하는 방법은 다음과 같습니다.

document
  .getElementById('targetFrame')
  .contentDocument
  .defaultView
  .targetFunction();

(못생긴 줄 바꿈에 대해 죄송하지만 한 줄에 맞지 않았습니다)


8

IFRAME은 frames[]컬렉션에 있어야합니다 . 같은 것을 사용하십시오

frames['iframeid'].method();

이 답변은 확실히 다른 고려 사항이 있기 때문에 더 많은 정보를 사용할 수 있습니다. 우선, 개발자가 methodiframe window객체 의 속성 을 만들어야한다고 가정 합니다.
— matty

8

Quirksmode는 이것에 대해 글을 올렸습니다 .

페이지가 이제 깨져서 archive.org를 통해서만 액세스 할 수 있으므로 여기에서 재현했습니다.

IFrames

이 페이지에서는 현재 페이지에서 iframe에 액세스하는 방법에 대한 간단한 개요를 제공합니다. 당연히 브라우저 고려 사항이 몇 가지 있습니다.

iframe은 인라인 프레임으로, 자체 URL이있는 완전히 별도의 페이지가 포함되어 있지만 다른 HTML 페이지 내에 배치되는 프레임입니다. 이것은 웹 디자인에서 매우 좋은 가능성을 제공합니다. 문제는 iframe에 액세스하는 것입니다. 예를 들어 iframe에 새 페이지를로드하는 것입니다. 이 페이지는 방법을 설명합니다.

프레임이나 대상?

근본적인 질문은 iframe이 프레임 또는 객체로 보이는지 여부입니다.

  • 프레임 소개 페이지 에 설명 된대로 프레임 을 사용하면 브라우저에서 프레임 계층을 만듭니다 (top.frames[1].frames[2] . iframe이이 프레임 계층에 맞습니까?
  • 또는 브라우저가 iframe을 src 속성을 갖는 객체 인 다른 객체로만 보입니까? 이 경우 표준 DOM 호출 (예 document.getElementById('theiframe')): 액세스)을 사용해야합니다. 일반적으로 브라우저는 '실제'(하드 코딩 된) iframe에 대한 두보기를 모두 허용하지만 생성 된 iframe은 프레임으로 액세스 할 수 없습니다.

NAME 속성

가장 중요한 규칙은을 name사용하더라도 속성 을 생성하는 모든 iframe을 제공 하는 것 id입니다.

<iframe src="iframe_page1.html"
    id="testiframe"
    name="testiframe"></iframe>

대부분의 브라우저 name는 iframe을 프레임 계층의 일부로 만들 려면 속성이 필요합니다 . 일부 브라우저 (특히 Mozilla) id는 iframe을 객체로 액세스 할 수 있도록하기 위해를 필요 로합니다. iframe에 두 속성을 모두 지정하면 옵션을 계속 열어 둘 수 있습니다. 그러나 name보다 훨씬 더 중요합니다 id.

접속하다

iframe을 객체로 액세스하고 객체를 변경 src하거나 iframe을 프레임으로 액세스하여 객체 를 변경합니다 location.href.

document.getElementById ( 'iframe_id'). src = 'newpage.html'; frames [ 'iframe_name']. location.href = 'newpage.html'; 프레임 구문은 Opera 6이 지원하지만 객체 구문은 지원하지 않기 때문에 약간 선호됩니다.

iframe에 액세스

따라서 완벽한 크로스 브라우저 경험을 위해서는 iframe에 이름을 지정하고

frames['testiframe'].location.href

통사론. 내가 아는 한 항상 작동합니다.

문서에 액세스

name속성 을 사용하면 iframe 내부의 문서에 액세스하는 것이 매우 간단 합니다. iframe에서 문서의 링크 수를 계산하려면을 수행하십시오 frames['testiframe'].document.links.length.

생성 된 iframe

W3C DOM을 통해 iframe을 생성하면 iframe 이 즉시 frames배열에 입력되지 않습니다 .frames['testiframe'].location.href 되지 않으며 구문이 즉시 작동하지 않습니다. 브라우저가 iframe이 배열에서 나타나기 전에 약간의 시간이 필요하며,이 시간 동안 스크립트가 실행될 수 없습니다.

document.getElementById('testiframe').src모든 상황에서 구문 이 제대로 작동합니다.

target링크 의 속성은 생성 된 iframe에 a name와 a를 모두 제공했지만 Opera를 제외하고 생성 된 iframe에서 작동하지 않습니다 id.

target지원 이 없다는 것은 생성 된 iframe의 컨텐츠를 변경하기 위해 JavaScript를 사용해야한다는 것을 의미하지만, 어쨌든 JavaScript를 생성하기 위해서는 JavaScript가 필요하기 때문에 이것이 큰 문제가되지는 않습니다.

iframe의 텍스트 크기

호기심 많은 Explorer 6 전용 버그 :

보기 메뉴를 통해 텍스트 크기를 변경하면 iframe의 텍스트 크기가 올바르게 변경됩니다. 그러나이 브라우저는 원본 텍스트의 줄 바꿈을 변경하지 않으므로 텍스트의 일부가 보이지 않거나 줄 바꿈이 발생하는 동안 줄이 다른 단어를 가질 수 있습니다.


5
링크가 끊어진 것 같습니다.
— zaphod 2016 년

1
그리고 설상가상으로, quirksmode에서 관련 페이지를 찾을 수 없습니다.
— stricjux


7

나는 매우 우아한 해결책을 찾았습니다.

당신이 말했듯이, 부모 문서에있는 코드를 실행하는 것은 상당히 쉽습니다. 그리고 그것은 내 코드의 기초입니다. 반대로하십시오.

내 iframe 이로 드되면 부모 문서에있는 함수를 호출하여 iframe의 문서에있는 로컬 함수에 대한 참조를 인수로 전달합니다. 부모 문서는 이제이 참조를 통해 iframe의 기능에 직접 액세스 할 수 있습니다.

예:

부모님 :

function tunnel(fn) {
    fn();
}

iframe에서 :

var myFunction = function() {
    alert("This work!");
}

parent.tunnel(myFunction);

iframe이로드되면 parent.tunnel (YourFunctionReference)을 호출하여 매개 변수에서 수신 된 함수를 실행합니다.

다양한 브라우저의 모든 비표준 방법을 처리하지 않고도 간단합니다.


안녕하세요, "다양한 브라우저의 모든 비표준 방법을 다룰 필요없이 간단합니다."
— Milche Patern

1
나는이 방법을 다양한 프로젝트에서 사용하며 매우 잘 작동하는 것 같습니다. 나는 모든 브라우저를 개인적으로 테스트하지는 않았지만 버그 보고서를 얻지 못했습니다.
— Julien L

매력, IE 11, Chrome ~ 50처럼 작동합니다.
— Augustas

1
교차 도메인이 아닌 것 같아요?
— Tushar Shukla 2016

불행히도 아닙니다.
— jeff-h

6

이러한 답변 중 일부는 CORS 문제를 해결하지 못하거나 통신을 가능하게하기 위해 코드 스 니펫을 어디에 배치했는지 분명하게 밝히지 않습니다.

구체적인 예는 다음과 같습니다. 부모 페이지에서 버튼을 클릭하고 iframe 내부에서 무언가를 수행한다고 가정 해보십시오. 내가하는 방법은 다음과 같습니다.

parent_frame.html

<button id='parent_page_button' onclick='call_button_inside_frame()'></button>

function call_button_inside_frame() {
   document.getElementById('my_iframe').contentWindow.postMessage('foo','*');
}

iframe_page.html

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
    {
      if(event) {
        click_button_inside_frame();
    }
}

function click_button_inside_frame() {
   document.getElementById('frame_button').click();
}

다른 방향으로 이동하려면 (iframe 내부의 버튼을 클릭하여 iframe 외부의 메소드를 호출하십시오) 코드 스 니펫이 살고있는 곳을 전환하고 다음을 변경하십시오.

document.getElementById('my_iframe').contentWindow.postMessage('foo','*');

이에:

window.parent.postMessage('foo','*')

4

JoelAnair의 답변을 계속하십시오 .

견고성을 높이려면 다음과 같이 사용하십시오.

var el = document.getElementById('targetFrame');

if(el.contentWindow)
{
   el.contentWindow.targetFunction();
}
else if(el.contentDocument)
{
   el.contentDocument.targetFunction();
}

매력처럼 작동했습니다 :)


3

니틴 반 살의 대답

그리고 더욱 견고성을 위해 :

function getIframeWindow(iframe_object) {
  var doc;

  if (iframe_object.contentWindow) {
    return iframe_object.contentWindow;
  }

  if (iframe_object.window) {
    return iframe_object.window;
  } 

  if (!doc && iframe_object.contentDocument) {
    doc = iframe_object.contentDocument;
  } 

  if (!doc && iframe_object.document) {
    doc = iframe_object.document;
  }

  if (doc && doc.defaultView) {
   return doc.defaultView;
  }

  if (doc && doc.parentWindow) {
    return doc.parentWindow;
  }

  return undefined;
}

과

...
var el = document.getElementById('targetFrame');

var frame_win = getIframeWindow(el);

if (frame_win) {
  frame_win.targetFunction();
  ...
}
...

2
       $("#myframe").load(function() {
            alert("loaded");
        });

2

같은 일이지만 조금 더 쉬운 방법은 iframe 내의 페이지에서 부모 페이지를 새로 고치는 방법입니다 . 부모 페이지의 함수를 호출하여 자바 스크립트 함수를 호출하여 페이지를 다시로드하십시오.

window.location.reload();

또는 iframe의 페이지에서 직접 수행하십시오.

window.parent.location.reload();

둘 다 작동합니다.



1

다른 함수 ex shadowbox 또는 lightbox에 의해 생성 된 iframe에서 Parent의 JavaScript 함수를 호출하려는 경우.

window객체를 사용 하고 부모 함수를 호출 해야 합니다.

window.parent.targetFunction();

나는 OP가 다른 방향으로 가고 있다고 생각합니다
— CommandZ

-3

다음을 사용하여 부모 페이지에서 프레임의 함수를 호출하십시오.

parent.document.getElementById('frameid').contentWindow.somefunction()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.