親ページからiframeでJavaScriptコードを呼び出す


615

基本的に、私はiframeページに埋め込まれていiframeて、親ページから呼び出す必要があるいくつかのJavaScriptルーチンがあります。

今は、を呼び出すだけでよいので、その反対は非常に簡単ですparent.functionName()が、残念ながら、私はそれとは正反対のことが必要です。

私の問題はのソースURLを変更するのではなく、iframeで定義された関数を呼び出すことiframeです。


42
parent.fuctioName()に関するメモは、iframeの親htmlで関数を呼び出すという私の問題を解決しました。ありがとう!
Cyber​​Fonic

1
探しているiframeへの参照があることを確認したい場合は、デバッグ時にwindow.location.hrefやparent.location.hrefなどを実行してiframeのURLを表示できます。
AaronLS 2013年

@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');"remote_iframe_0が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 2013

8
@JellicleCatこれは、メッセージが示すように、親ページとiframeのホストが異なるため、クロスオリジンフレームになっているためです。親ページのプロトコル、ドメイン、ポートとiframeが一致している限り、すべてが正常に機能します。
マークアメリー2014年

1
上記のwindow.framesメソッドの使用例を追加しました。
イライジャ・リン

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が1つしかないことがわかっている場合。

  5. 子iframeがまだロードされていないか、何かに問題が発生してアクセスできなくなっている可能性があります。通信の流れを逆にする方が簡単な場合があります。つまり、window.parentロードが完了してコールバックの準備ができたときに、子iframeにスクリプトに通知させます。独自のオブジェクト(コールバック関数など)の1つを親スクリプトに渡すことにより、その親は、関連付けられている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 2014年

@chovy:いいえ、これに関するVivekの回答の説明を参照してください。
ボビンス2014年

66

から親JS関数を呼び出すことiframeは可能ですが、親とロードされたページのiframe両方が同じドメイン、つまりabc.comからのもので、両方が同じプロトコルを使用している場合、つまり両方がかのどちらかであるhttp://場合に限りますhttps://

以下の場合、呼び出しは失敗します。

  1. 親ページとiframeページは異なるドメインのものです。
  2. 彼らは異なるプロトコルを使用しています。1つはhttp://にあり、もう1つはhttps://にあります。

この制限に対する回避策は非常に安全ではありません。

たとえば、superwinningcontest.comというドメインを登録して、人々のメールへのリンクを送信したとします。彼らがメインページをロードしたとき、私はiframeそこにいくつかのsを隠してFacebookフィードを読んだり、最近のAmazonやPayPalの取引をチェックしたり、十分なセキュリティを実装していないサービスを使用した場合は、彼らからお金を送金したりできます。アカウント。これが、JavaScriptが同じドメインと同じプロトコルに制限されている理由です。


6
回避策は、美しくて危険なen.wikipedia.org/wiki/Cross-document_messaging
Laramie

別のサブドメインが原因でこれが失敗するかどうか誰かが知っていますか?これに関連すると思われる問題のデバッグが困難です。iframeが親ウィンドウ関数を呼び出していますが、呼び出しは行われていません。
ジェイク

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イベントのように動作するようにするにはどうすればよいですか?
カール

1
@Karl呼び出したくないonclick。あなたが電話したいiframe.contentWindow.print()
Tomalak 2012

残念ながら、それは機能しません。多分私は新しい質問を始めて私のコードを文書化するべきですか?いずれにしても、親ページのコンテンツも印刷されます。document.getElementById('myFrame').contentWindow.print();' and the pubic function 呼び出すprintContent() `(oncickイベントハンドラーではない)window.print()は次のように呼び出されました:document.getElementById('myFrame').contentWindow.printContent();
Karl

1
@Karl-はい、新しい質問を始めるのが最善です。親ウィンドウがiframeとは異なるドメインにある場合を除きます。その後、あなたがしようとすることは決してうまくいきません
Tomalak 2012

ここで報告したのは、IEの問題(IE8でのテスト)のようです。現在のバージョンのChromeでは問題ありません。ただし、他のブラウザをまだテストしていない。興味のある方は、このjsFiddleを参照してください(これは、動的なiframeの読み込みと親からのパブリック関数の呼び出しの良い例だと思います。)
Karl

20

iFrameのターゲットとそれを含むドキュメントが異なるドメインにある場合、以前に投稿されたメソッドは機能しない可能性がありますが、解決策があります:

たとえば、ドキュメントAにドキュメントBを含むiframe要素が含まれ、ドキュメントAのスクリプトがドキュメントBのウィンドウオブジェクトでpostMessage()を呼び出す場合、そのオブジェクトでメッセージイベントが発生し、ウィンドウのドキュメントA。ドキュメント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は、古いブラウザ用のPostMessageの抽象化を提供します(頑固な恐竜用のFlash(LocalConnection)フォールバックを含む)。
JonnyReeves

1
それは素晴らしいです...上記の回答を試した後、最終的に私はあなたの回答を得ました
vkGunasekaran

9

参考までに、今日同じ問題に遭遇しましたが、今回はページがiframeではなくオブジェクトに埋め込まれていました(XHTML 1.1ドキュメントであるため)。オブジェクトでの動作は次のとおりです。

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

(醜い改行のため申し訳ありません、単一の行に収まりませんでした)


8

IFRAMEはframes[]コレクションに含まれている必要があります。のようなものを使う

frames['iframeid'].method();

確かに他の考慮事項がいくつかあるので、この答えは確かにさらに多くの情報を使用する可能性があります。1つmethodは、開発者がiframeのwindowオブジェクトのプロパティを作成する必要があることです。
matty

8

Quirksmodeがこれについて投稿しました

このページは壊れており、archive.orgからのみアクセスできるため、ここに再現しました。

iFrame

このページでは、iframeが表示されているページからiframeにアクセスする方法の概要を説明します。当然のことながら、ブラウザに関する考慮事項がいくつかあります。

iframeはインラインフレームであり、独自のURLを持つ完全に別のページを含みながら、別のHTMLページ内に配置されるフレームです。これにより、Webデザインに非常に優れた可能性が生まれます。問題は、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>

ほとんどのブラウザでは、nameiframeをフレーム階層の一部にするために属性が必要です。一部のブラウザー(特に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との両方を指定した場合でも、Operaを除いて、生成されたiframeでは機能しませんid

targetサポートの欠如は、生成されたiframeのコンテンツを変更するためにJavaScriptを使用する必要があることを意味しますが、そもそもJavaScriptを生成してそれを生成する必要があるため、これはそれほど問題にはなりません。

iframe内のテキストサイズ

奇妙なExplorer 6のみのバグ:

[表示]メニューでテキストサイズを変更すると、iframe内のテキストサイズが正しく変更されます。ただし、このブラウザは元のテキストの改行を変更しないため、テキストの一部が表示されない場合や、行が別の単語を保持しているときに改行が発生する場合があります。


5
そのリンクは壊れているようです。
zaphod

1
さらに悪いことに、私は関連ページをquirksmodeのどこにも見つけることができません。
stricjux 2009


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のように機能します。
オーガスタ2016年

1
それはクロスドメインではないと思います。
Tushar Shukla

@TusharShukla残念ながら、違います。
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

Nitin Bansalの回答をフォローする

さらに堅牢性を高めるために:

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

同じことですが、少し簡単な方法は、iframe内のページから親ページを更新する方法です。親ページの関数を呼び出して、JavaScript関数を呼び出し、ページをリロードするだけです。

window.location.reload();

または、iframeのページから直接これを実行します。

window.parent.location.reload();

どちらも機能します。



1

シャドウボックスやライトボックスなどの別の関数によって生成されたiframeから、親のJavaScript関数を呼び出す場合。

あなたはwindowオブジェクトを利用して親関数を呼び出そうとする必要があります:

window.parent.targetFunction();

OPは別の方向に向かっていると
思い

-3

次を使用して親ページのフレームの関数を呼び出します

parent.document.getElementById('frameid').contentWindow.somefunction()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.