부모 페이지에서 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.