基本的に、私はiframe
をページに埋め込み、iframe
は親ページから呼び出す必要のある JavaScript /ルーチンをいくつか持っています。
parent.functionName()
を呼び出すだけでよいので、今度はその逆が非常に単純ですが、残念ながら、その逆が必要です。
私の問題はiframe
のソース _ url _ を変更するのではなく、iframe
で定義された関数を呼び出すことです。
あなたの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();
ここで知っておくべきいくつかの癖があります。
HTMLIFrameElement.contentWindow
はおそらくもっと簡単な方法ですが、これは標準的なプロパティではなく、ブラウザによってはそれをサポートしていないものもあります。これはDOM Level 1 HTML標準がwindow
オブジェクトについて何も言うことがないからです。
また、HTMLIFrameElement.contentDocument.defaultView
を試すこともできます。古いブラウザでは許可されていますがIEでは許可されていません。それでも、(1)と同じ理由で、標準ではwindow
オブジェクトを取り戻すとは明示的には言われていませんが、気になる場合はここでいくつかの追加のブラウザバージョンを選択できます。
ウィンドウを返すwindow.frames['name']
は、最も古く、したがって最も信頼できるインタフェースです。しかし、名前でフレームを取得できるようにするには、name="..."
属性を使用する必要があります。これは、やや見苦しいです。廃止予定/過渡期。 (id="..."
の方が良いでしょうが、IEはそれが好きではありません。)
window.frames[number]
もまた非常に信頼性がありますが、正しいインデックスを知ることがトリックです。あなたはこれで逃げることができます例えば。あなたが知っていればあなたはページ上に1つのiframeしか持っていません。
子iframeがまだロードされていないか、他のものがアクセス不能にするために間違っていた可能性があります。通信の流れを逆にした方が簡単な場合があります。つまり、ロードが完了してコールバックの準備ができたときに、子iframeにwindow.parent
スクリプトを通知させることです。独自のオブジェクトの1つ(たとえばコールバック関数)を親スクリプトに渡すことで、その親は、それが関連付けられているHTMLIFrameElementを気にせずに、iframe内のスクリプトと直接通信できます。
iframe
から親JS関数を呼び出すことは可能ですが、iframe
にロードされた親とページの両方が同じドメイン(abc.com)からのものであり、両方が同じプロトコルを使用している、つまり両方がhttp://
またはhttps://
のいずれかにある場合のみです。
以下のケースでは、呼び出しは失敗します。
この制限に対する回避策は非常に安全ではありません。
たとえば、superwinningcontest.comというドメインを登録し、人々のEメールへのリンクを送信したとします。メインページを開いたら、そこにいくつかのiframe
を隠して最近のAmazonやPaypalの取引をチェックしたり、あるいは十分なセキュリティを実装していないサービスを使っていた場合は自分のお金を送ってアカウントJavaScriptが同一ドメインおよび同一プロトコルに限定されているのはそのためです。
IFRAMEでは、関数をウィンドウオブジェクトに対してパブリックにします。
window.myFunction = function(args) {
doStuff();
}
親ページからアクセスするには、これを使用します。
var iframe = document.getElementById("iframeId");
iframe.contentWindow.myFunction(args);
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);
}
}
}
このスクリプトは、最初にドメインが予想されるドメインであることを確認してから、ユーザーに表示されるか、メッセージを最初に送信した文書に返信することによって応答するメッセージを調べます。
ただ記録のために、私は今日同じ問題に遭遇した、しかし今回はページがオブジェクトではなく、iframeではなく埋め込まれた(それがXHTML 1.1文書であったので)。これがオブジェクトとどのように連携するのかを説明します。
document
.getElementById('targetFrame')
.contentDocument
.defaultView
.targetFunction();
(醜い改行がすみません、一行に収まりませんでした)
Quirksmodeは に投稿しました 。
このページは現在壊れていて、archive.org経由でしかアクセスできないので、ここで再現しました。
IFrames
このページでは、自分がいるページからiframeにアクセスする方法について簡単に説明します。当然のことながら、ブラウザに関する考慮事項がいくつかあります。
Iframeはインラインフレームです。インラインフレームは、独自のURLを持つ完全に独立したページを含みながら、別のHTMLページ内に配置されるフレームです。これはWebデザインにおいて非常に素晴らしい可能性を与えます。問題は、iframeにアクセスして、たとえば新しいページをそこにロードすることです。このページではその方法を説明しています。
フレームまたはオブジェクト?
根本的な問題は、iframeがフレームとして見られるのかオブジェクトとして見られるのかということです。
top.frames[1].frames[2]
など)。 iframeはこのフレーム階層に適合しますか?document.getElementById('theiframe'))
のように)を使用しなければなりません。NAME属性
最も重要な規則は、name
も使用していても、作成したiframeにid
属性を指定することです。
<iframe src="iframe_page1.html"
id="testiframe"
name="testiframe"></iframe>
ほとんどのブラウザは、iframeをフレーム階層の一部にするためにname
属性を必要とします。一部のブラウザ(特にMozilla)は、iframeをオブジェクトとしてアクセス可能にするためにid
を必要とします。両方の属性を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
構文はあらゆる状況でうまく機能します。
私が生成したiframeにtarget
とname
の両方を与えたとしても、リンクのid
属性は、Operaを除いて、生成されたiframeのどちらでも動作しません。
target
のサポートがないということは、生成されたiframeの内容を変更するためにJavaScriptを使用しなければならないことを意味しますが、そもそもそれを生成するためにはJavaScriptが必要です。
iframe内のテキストサイズ
奇妙なExplorer 6だけのバグ:
表示メニューでテキストサイズを変更すると、iframeのテキストサイズが正しく変更されます。ただし、このブラウザでは元のテキストの改行は変更されないため、テキストの一部が表示されなくなったり、改行が発生しても別のWordを保持できます。
IFRAMEはframes[]
コレクションになければなりません。のようなものを使う
frames['iframeid'].method();
私はかなり優雅な解決策を見つけました。
あなたが言ったように、親文書にあるコードを実行することはかなり簡単です。これが私のコードの基本です。逆にしてください。
私のiframeがロードされるとき、私は親ドキュメントにある関数を呼び出し、iframeのドキュメントにあるローカル関数への参照を引数として渡します。この参照を通じて、親文書はiframeの関数に直接アクセスできるようになりました。
例:
親に:
function tunnel(fn) {
fn();
}
Iframeについて:
var myFunction = function() {
alert("This work!");
}
parent.tunnel(myFunction);
Iframeがロードされると、それはparent.tunnel(YourFunctionReference)を呼び出します。これはparameterで受け取った関数を実行します。
いろいろなブラウザからのすべての非標準的な方法を扱う必要なしでそれは簡単です。
これらの回答の中には、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','*')
JoelAnairの answerを続けて:
より堅牢にするには、次のように使用します。
var el = document.getElementById('targetFrame');
if(el.contentWindow)
{
el.contentWindow.targetFunction();
}
else if(el.contentDocument)
{
el.contentDocument.targetFunction();
}
魅力のように働いた:)
フォロー中の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();
...
}
...
同じことだが、もう少し簡単な方法は iframe内のページから親ページを更新する方法 です。親ページの関数を呼び出してjavascript関数を呼び出してページをリロードするだけです。
window.location.reload();
またはiframeのページから直接これを行います。
window.parent.location.reload();
どちらも動作します。
$("#myframe").load(function() {
alert("loaded");
});
parent.myfunction()
だけを試してください
コーディングから生成したiframeから親ページのjavascript関数を呼び出したい場合。元shadowboxまたはlightbox
window.parent.targetFunction();