web-dev-qa-db-ja.com

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

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

parent.functionName()を呼び出すだけでよいので、今度はその逆が非常に単純ですが、残念ながら、その逆が必要です。

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

579
Tamas Czinege

あなたの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(); 
521
Joel Anair

ここで知っておくべきいくつかの癖があります。

  1. HTMLIFrameElement.contentWindowはおそらくもっと簡単な方法ですが、これは標準的なプロパティではなく、ブラウザによってはそれをサポートしていないものもあります。これはDOM Level 1 HTML標準がwindowオブジェクトについて何も言うことがないからです。

  2. また、HTMLIFrameElement.contentDocument.defaultViewを試すこともできます。古いブラウザでは許可されていますがIEでは許可されていません。それでも、(1)と同じ理由で、標準ではwindowオブジェクトを取り戻すとは明示的には言われていませんが、気になる場合はここでいくつかの追加のブラウザバージョンを選択できます。

  3. ウィンドウを返すwindow.frames['name']は、最も古く、したがって最も信頼できるインタフェースです。しかし、名前でフレームを取得できるようにするには、name="..."属性を使用する必要があります。これは、やや見苦しいです。廃止予定/過渡期。 (id="..."の方が良いでしょうが、IEはそれが好きではありません。)

  4. window.frames[number]もまた非常に信頼性がありますが、正しいインデックスを知ることがトリックです。あなたはこれで逃げることができます例えば。あなたが知っていればあなたはページ上に1つのiframeしか持っていません。

  5. 子iframeがまだロードされていないか、他のものがアクセス不能にするために間違っていた可能性があります。通信の流れを逆にした方が簡単な場合があります。つまり、ロードが完了してコールバックの準備ができたときに、子iframeにwindow.parentスクリプトを通知させることです。独自のオブジェクトの1つ(たとえばコールバック関数)を親スクリプトに渡すことで、その親は、それが関連付けられているHTMLIFrameElementを気にせずに、iframe内のスクリプトと直接通信できます。

141
bobince

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

以下のケースでは、呼び出しは失敗します。

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

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

たとえば、superwinningcontest.comというドメインを登録し、人々のEメールへのリンクを送信したとします。メインページを開いたら、そこにいくつかのiframeを隠して最近のAmazonやPaypalの取引をチェックしたり、あるいは十分なセキュリティを実装していないサービスを使っていた場合は自分のお金を送ってアカウントJavaScriptが同一ドメインおよび同一プロトコルに限定されているのはそのためです。

64

IFRAMEでは、関数をウィンドウオブジェクトに対してパブリックにします。

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

親ページからアクセスするには、これを使用します。

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

IFrameとそれを含む文書が別のドメインにある場合は、以前にポストされたメソッドは機能しない可能性がありますが、解決策があります。

たとえば、文書Aに文書Bを含むiframe要素が含まれていて、文書Aのスクリプトが文書BのWindowオブジェクトに対してpostMessage()を呼び出すと、そのオブジェクトに対してmessageイベントが発生します。文書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 による

16
19greg96

ただ記録のために、私は今日同じ問題に遭遇した、しかし今回はページがオブジェクトではなく、iframeではなく埋め込まれた(それがXHTML 1.1文書であったので)。これがオブジェクトとどのように連携するのかを説明します。

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

(醜い改行がすみません、一行に収まりませんでした)

9
Tamas Czinege

Quirksmodeは に投稿しました

このページは現在壊れていて、archive.org経由でしかアクセスできないので、ここで再現しました。

IFrames

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

Iframeはインラインフレームです。インラインフレームは、独自のURLを持つ完全に独立したページを含みながら、別のHTMLページ内に配置されるフレームです。これはWebデザインにおいて非常に素晴らしい可能性を与えます。問題は、iframeにアクセスして、たとえば新しいページをそこにロードすることです。このページではその方法を説明しています。

フレームまたはオブジェクト?

根本的な問題は、iframeがフレームとして見られるのかオブジェクトとして見られるのかということです。

  • フレームの紹介 ページで説明したように、フレームを使用している場合は、ブラウザによってフレーム階層が作成されます(top.frames[1].frames[2]など)。 iframeはこのフレーム階層に適合しますか?
  • それともブラウザはiframeを単なる別のオブジェクト、srcプロパティを持っているオブジェクトと見なしますか?その場合は、標準の DOM呼び出し (アクセスするにはdocument.getElementById('theiframe'))のように)を使用しなければなりません。

NAME属性

最も重要な規則は、nameも使用していても、作成したiframeにid属性を指定することです。

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

ほとんどのブラウザは、iframeをフレーム階層の一部にするためにname属性を必要とします。一部のブラウザ(特にMozilla)は、iframeをオブジェクトとしてアクセス可能にするためにidを必要とします。両方の属性をiframeに割り当てることで、オプションを開いたままにします。しかしnameidよりはるかに重要です。

アクセス

オブジェクトとして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構文はあらゆる状況でうまく機能します。

私が生成したiframeにtargetnameの両方を与えたとしても、リンクのid属性は、Operaを除いて、生成されたiframeのどちらでも動作しません。

targetのサポートがないということは、生成されたiframeの内容を変更するためにJavaScriptを使用しなければならないことを意味しますが、そもそもそれを生成するためにはJavaScriptが必要です。

iframe内のテキストサイズ

奇妙なExplorer 6だけのバグ:

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

8
activout.se

IFRAMEはframes[]コレクションになければなりません。のようなものを使う

frames['iframeid'].method();
8
dkretz

私はかなり優雅な解決策を見つけました。

あなたが言ったように、親文書にあるコードを実行することはかなり簡単です。これが私のコードの基本です。逆にしてください。

私のiframeがロードされるとき、私は親ドキュメントにある関数を呼び出し、iframeのドキュメントにあるローカル関数への参照を引数として渡します。この参照を通じて、親文書はiframeの関数に直接アクセスできるようになりました。

例:

親に:

function tunnel(fn) {
    fn();
}

Iframeについて:

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

parent.tunnel(myFunction);

Iframeがロードされると、それはparent.tunnel(YourFunctionReference)を呼び出します。これはparameterで受け取った関数を実行します。

いろいろなブラウザからのすべての非標準的な方法を扱う必要なしでそれは簡単です。

7
Julien L

これらの回答の中には、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
Cybernetic

JoelAnairの answerを続けて:

より堅牢にするには、次のように使用します。

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

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

魅力のように働いた:)

3
Nitin Bansal

フォロー中の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();
  ...
}
...
3

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

window.location.reload();

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

window.parent.location.reload();

どちらも動作します。

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

parent.myfunction()だけを試してください

1
Saeid Zebardast

コーディングから生成したiframeから親ページのjavascript関数を呼び出したい場合。元shadowboxまたはlightbox

window.parent.targetFunction();

1
Santhanakumar