Üst sayfadan iframe'de JavaScript kodu çağırma


615

Temelde, iframebir sayfada gömülü var ve üst sayfadan çağırmak için gereken iframebazı JavaScript rutinleri var.

Şimdi tam tersi, sadece aramanız gereken kadar basit parent.functionName(), ama maalesef tam tersine ihtiyacım var.

Benim sorunum kaynağı değişmiyor unutmayınız URL'yi arasında iframe, ancak tanımlanan bir fonksiyonu çağıran iframe.


42
Parent.fuctioName () ile ilgili notunuz, iframe'in üst html'sinde bir işlev çağırma sorunumu çözdü. Thanx!
CyberFonic

1
Hata ayıklama sırasında, aradığınız iframe'e bir referansınız olduğunu doğrulamak istiyorsanız, iframe'in url'sini görüntülemek için window.location.href veya parent.location.href gibi şeyleri yapabileceğinizi unutmayın.
AaronLS

Bkz. @Le dorfier'in Cevabı ... benim için mükemmel çalıştı.
ErickBest

Yanıtlar:


542

İFrame'inizin kimliğinin "targetFrame" olduğunu ve aramak istediğiniz işlevin targetFunction():

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

Bunun window.framesyerine çerçeveye de erişebilirsiniz 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 ve Safari'de çalışır (bu sürümden emin değilim)
Darcy

3
Bu çözüm gadget'ım için çalışmıyor, işte kodum document.getElementById('remote_iframe_0').contentWindow.my.create_element_gadg‌​et('verify_user');"remote_iframe_0 bir apache shindig sunucusu tarafından programlı olarak oluşturuldu, ancak window.parent.document.getElementById('remote_iframe_0').contentWindow.my.create_element_gadg‌​et('verify_user');"çalışıyor
J Bourne

3
@ Kirli Henry "jQuery işlevi" ile ne demek istiyorsun? jQuery bir JavaScript kütüphanesidir.
Joel Anair

8
@JellicleCat Üst sayfanın ve iframe'in farklı ana bilgisayarlara sahip olması, mesajın size söylediği gibi, bunu çapraz kökenli bir çerçeve haline getirmesidir. Üst sayfanın protokolü, etki alanı ve bağlantı noktası ile iframe eşleştiği sürece, her şey iyi çalışır.
Mark Amery

1
Bahsedilen window.frames yönteminin nasıl kullanılacağına dair bir örnek ekledim.
Elijah Lynn

145

Burada dikkat edilmesi gereken bazı tuhaflıklar var.

  1. HTMLIFrameElement.contentWindowmuhtemelen daha kolay bir yoldur, ancak standart bir özellik değildir ve bazı tarayıcılar bunu desteklemez, çoğunlukla daha eski olanları. Bunun nedeni, DOM Düzey 1 HTML standardının windownesne hakkında söylenecek bir şeyi olmamasıdır .

  2. Birkaç HTMLIFrameElement.contentDocument.defaultVieweski tarayıcının izin verdiği ancak IE'nin izin vermediğini de deneyebilirsiniz . Yine de, standart açıkça window(1) ile aynı nedenden ötürü nesneyi geri aldığınızı söylemez , ancak ilgilenirseniz burada birkaç ekstra tarayıcı sürümü alabilirsiniz.

  3. window.frames['name']pencereyi döndürmek en eski ve dolayısıyla en güvenilir arayüzdür. Ancak daha sonra name="...", biraz çirkin / kullanımdan kaldırılmış / geçişli bir adla çerçeve elde etmek için bir özellik kullanmanız gerekir . ( id="..."daha iyi olurdu ama IE bunu sevmiyor.)

  4. window.frames[number]aynı zamanda çok güvenilir, ancak doğru endeksi bilmek hiledir. Örneğin bununla kurtulabilirsiniz. sayfada yalnızca bir iframe bulunduğunu biliyorsanız.

  5. Çocuk iframe'i henüz yüklenmemiş olabilir veya erişilemez hale getirmek için başka bir şey ters gitti. İletişim akışını tersine çevirmeyi daha kolay bulabilirsiniz: yani, alt iframe window.parentyüklendiğinde ve geri çağrılmaya hazır olduğunda çocuk iframe'inin komut dosyasını bilgilendirmesini sağlayın. Üst nesneye kendi nesnelerinden birini (örn. Geri arama işlevi) ileterek, söz konusu üst öğe, hangi HTMLIFrameElement öğesinin ilişkili olduğu konusunda endişelenmenize gerek kalmadan iframe'deki komut dosyasıyla doğrudan iletişim kurabilir.


13
Harika şeyler! Özellikle öneriniz 5. son derece değerli olduğunu göstermiştir. Chrome'daki üst öğeden iFrame işlevlerine erişmeye çalışırken bana birçok baş ağrısını çözdü. İşlev nesnesini iFrame'den geçirmek, Chrome, FF ve hatta IE'de 9'dan 7'ye kadar bir cazibe gibi çalışmasını sağladı ve ayrıca işlevin zaten yüklü olup olmadığını kontrol etmeyi çok kolay hale getirdi. Teşekkürler!
Jpsy

3 numara çalışır, ama eğer bunu yapmak daha iyi @ le dorfier onun yorumuna koydu. Parçaya dikkat edin methode().
ErickBest

Ayrıca, modern tarayıcılardaki güvenlik kısıtlamaları (test edilmiş FF29 ve Chrome34) nedeniyle, işlev çağrınızı yaptığınız yer için çok önemli olduğunu unutmayın. Sadece bir komut dosyası etiketinden veya $ (belge) .ready () işlevini çağırmak çalışmaz. Bunun yerine çağrıyı vücudun onload etiketinin içine veya başka bir yerde önerildiği gibi bir çapa <a href="javascript:doit();"> yapın </a> (bkz. Stackoverflow.com/questions/921387/… ). İşlev çağrısını bir komut dosyasına geri arama olarak geçirmek de genellikle işe yarar.
titusn

@chovy: Hayır, Vivek'in bu konudaki cevabındaki açıklamaya bakın.
bobince

66

Bir ebeveyn JS işlevinin çağrılması iframemümkündür, ancak ebeveyn ve yüklenen sayfa hem yalnızca iframeaynı etki yani abc.com gelen ve her ikisi hem yani aynı protokolü kullanan ya vardır http://ya https://.

Aşağıdaki durumlarda arama başarısız olacaktır:

  1. Üst sayfa ve iframe sayfası farklı alanlardan.
  2. Farklı protokoller kullanıyorlar, biri http: // ve diğeri https: //.

Bu kısıtlamaya yönelik herhangi bir geçici çözüm son derece güvensiz olacaktır.

Örneğin, superwinningcontest.com alan adını kaydettirdiğimi ve insanların e-postalarına bağlantılar gönderdiğimi düşünün. Ana sayfayı yüklediklerinde iframe, orada birkaç s gizleyebilir ve Facebook beslemelerini okuyabilir, son Amazon veya PayPal işlemlerini kontrol edebilir veya - yeterli güvenlik sağlamayan bir hizmet kullansaydı - hesapları. Bu nedenle JavaScript aynı alan adı ve aynı protokolle sınırlıdır.


6
Çözüm, güzel ve tehlikeli en.wikipedia.org/wiki/Cross-document_messaging
Laramie

Farklı bir alt alan adının bunun başarısız olmasına neden olup olmayacağını bilen var mı? Bununla ilgili olduğuna inandığım bir sorunu ayıklamakta zorluk çekiyorum - iframe bir üst pencere işlevi çağırıyor, ancak çağrı olmuyor.
Jake

1
Farklı bağlantı noktası numaraları için de başarısız olacağını unutmayın. ie abc.com:80! = abc.com:8080
prasanthv

31

IFRAME içinde, işlevinizi pencere nesnesine herkese açık hale getirin:

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

Üst sayfadan erişim için şunu kullanın:

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

Mükemmel cevap. Buradaki sözleşmeden emin değilim. Takip eden bir sorum var. Yeni bir soruya başlamam gerekirse, söyleyeceğim. Bir sorunum var. Sayfamın iframe'i dinamik olarak doldurulur. onclick()Etkinliği basitçe çağıran bir düğme içerir window.print(). Bu yazdırır içeriği arasında iframemükemmel. Ancak iframe'in sayfasının genel işlevi çağırdığında window.print()ve üst sayfa genel işlevi çağırdığında , üst öğenin içeriği yazdırılır. window.print()Genel işlevde çağrı onclickolaydaki gibi davranması için bunu nasıl kodlamalıyım?
Karl

1
@Karl Aramak istemiyorsun onclick. Aramak istiyorsun iframe.contentWindow.print().
Tomalak

Ne yazık ki, bu çalışmıyor. Belki yeni bir Soru başlatmalı ve kodumu belgelemeliyim? Her iki durumda da, üst sayfa içeriği de yazdırılır. document.getElementById('myFrame').contentWindow.print();' and the pubic function Bu şekilde çağrılan printContent () `(oncick olay işleyicisi değil) window.print()şu şekilde çağrıldı:document.getElementById('myFrame').contentWindow.printContent();
Karl

1
@Karl - Evet, yeni bir soru başlatmak en iyisidir. Üst pencere iframe'den farklı bir alanda değilse. O zaman denediğiniz hiçbir şey işe yaramayacaktır .
Tomalak

Burada bildirdiğim bir IE sorunu gibi görünüyor (IE8 test). Chrome'un mevcut sürümünde sorun yok. Ancak diğer tarayıcıları henüz test etmediler. Bu ilgi, bu bkz jsFiddle (bu dinamik iframe yükleme ve ebeveynden bir kamu işlevini çağırarak iyi bir örnektir olduğunu düşünüyorum.)
Karl

20

İFrame'in hedefi ve içeren belge farklı bir etki alanındaysa, daha önce yayınlanan yöntemler çalışmayabilir, ancak bir çözüm vardır:

Örneğin, A belgesi, B belgesini içeren bir iframe öğesi içeriyorsa ve A belgesindeki komut dosyası, B belgesinin Pencere nesnesine postMessage () çağırıyorsa, o nesneye, A belgesindeki komut dosyası şöyle görünebilir:

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

Gelen olaylar için bir olay işleyicisi kaydetmek için, komut dosyası addEventListener () (veya benzer mekanizmalar) kullanır. Örneğin, B belgesindeki komut dosyası şöyle görünebilir:

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);
    }
  }
}

Bu komut dosyası önce etki alanının beklenen etki alanı olup olmadığını denetler ve daha sonra kullanıcıya görüntülediği iletiye bakar veya iletiyi ilk etapta gönderen belgeye bir ileti göndererek yanıt verir.

http://dev.w3.org/html5/postmsg/#web-messaging yoluyla


1
easyXDM , eski tarayıcılar (inatçı dinozorlar için bir Flash (LocalConnection) yedeği dahil) için PostMessage üzerinden bir soyutlama sağlar.
JonnyReeves

1
Bu harika ... yukarıdaki cevapları denedikten sonra sonunda cevabını aldım, teşekkürler!
vkGunasekaran

9

Sadece kayıt için, bugün aynı sorunla karşılaştım, ancak bu sefer sayfa bir iframe'e değil, bir nesneye gömüldü (XHTML 1.1 belgesi olduğu için). Nesnelerle şu şekilde çalışır:

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

(çirkin satır sonları için özür dilerim, tek bir satıra sığmadı)


8

IFRAME frames[]koleksiyonda olmalıdır . Gibi bir şey kullan

frames['iframeid'].method();

Bu cevap kesinlikle daha fazla bilgi kullanabilir, çünkü başka düşünceler de vardır. Birincisi, geliştiricinin methodiframe windownesnesinin bir özelliğini yapması gerektiğini varsayıyorum .
matty

8

Quirksmode bu konuda bir yazı yayınladı .

Sayfa artık bozuk olduğundan ve yalnızca archive.org üzerinden erişilebilir olduğundan, burada çoğalttım:

IFrame'ler

Bu sayfada, bulundukları sayfadan iframe'lere erişmeye kısa bir genel bakış sunacağım. Şaşırtıcı olmayan bir şekilde, bazı tarayıcı hususları var.

Bir iframe satır içi bir çerçevedir, ancak kendi URL'sine sahip tamamen ayrı bir sayfa içerirken yine de başka bir HTML sayfasının içine yerleştirilen bir çerçevedir. Bu, web tasarımında çok güzel olanaklar sunar. Sorun, iframe'e erişmek, örneğin içine yeni bir sayfa yüklemek. Bu sayfada bunun nasıl yapılacağı açıklanmaktadır.

Çerçeve veya nesne?

Temel soru iframe'in bir çerçeve mi yoksa bir nesne olarak mı görüldüğü.

  • Çerçevelere giriş sayfalarında açıklandığı gibi , çerçeveler kullanırsanız tarayıcı sizin için ( top.frames[1].frames[2]ve benzeri) bir çerçeve hiyerarşisi oluşturur . İframe bu çerçeve hiyerarşisine uyuyor mu?
  • Yoksa tarayıcı bir iframe'i başka bir nesne, src özelliğine sahip bir nesne olarak mı görüyor? Bu durumda standart bir DOM çağrısı kullanmalıyız ( document.getElementById('theiframe'))erişmek gibi. Genel olarak tarayıcılar 'gerçek' (sabit kodlu) iframe'lerde her iki görünüme de izin verir, ancak oluşturulan iframe'lere çerçeve olarak erişilemez.

NAME özelliği

En önemli kural, bir nameöznitelik oluşturduğunuz herhangi bir iframe'i , bir de kullansanız bile vermektir id.

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

Çoğu tarayıcı nameiframe'i çerçeve hiyerarşisinin bir parçası yapmak için bu özelliğe ihtiyaç duyar . Bazı tarayıcıların (özellikle Mozilla'nın) idiframe'i bir nesne olarak erişilebilir hale getirmesi gerekir . Her iki özelliği de iframe'e atayarak seçeneklerinizi açık tutarsınız. Ancak namebundan çok daha önemlidir id.

Giriş

İframe'e bir nesne olarak srcerişirsiniz ve onun çerçevesini değiştirirsiniz veya iframe'e bir çerçeve olarak erişir ve bunu değiştirirsiniz location.href.

document.getElementById ('iframe_id'). src = 'newpage.html'; çerçeveler ['iframe_name']. location.href = 'newpage.html'; Çerçeve sözdizimi biraz tercih edilir, çünkü Opera 6 bunu destekler ancak nesne sözdizimini desteklemez.

İframe'e erişme

Bu nedenle, tam bir tarayıcılar arası deneyim için iframe'e bir ad vermeli ve

frames['testiframe'].location.href

sözdizimi. Bildiğim kadarıyla bu her zaman işe yarar.

Belgeye erişme

nameÖzelliği kullanmanız koşuluyla, iframe içindeki belgeye erişmek oldukça basittir . İframe'deki belgedeki bağlantı sayısını saymak için yapın frames['testiframe'].document.links.length.

Oluşturulan iframe'ler

W3C DOM aracılığıyla bir iframe oluşturduğunuzda, iframe framesdiziye hemen girilmez ve frames['testiframe'].location.hrefsözdizimi hemen çalışmaz. Tarayıcı, iframe dizide açılmadan önce, komut dizisinin çalışamayacağı zamana ihtiyaç duyar.

document.getElementById('testiframe').srcSözdizimi her koşulda cezası çalışır.

targetBir bağlantının niteliği benim iframe oluşturulan a hem elde ettiğini, ancak Opera dışında oluşturulan iframe'lerle da işe yaramıyor nameve bir id.

targetDestek eksikliği, oluşturulan bir iframe'in içeriğini değiştirmek için JavaScript kullanmanız gerektiği anlamına gelir, ancak ilk etapta onu oluşturmak için JavaScript'e zaten ihtiyacınız olduğundan, bunu bir sorun olarak görmüyorum.

İç çerçevelerde metin boyutu

Meraklı bir Explorer 6 sadece hatası:

Metin boyutunu Görünüm menüsünden değiştirdiğinizde, iframe'lerde metin boyutları doğru şekilde değiştirilir. Ancak, bu tarayıcı orijinal metindeki satır sonlarını değiştirmez, böylece metnin bir kısmı görünmez olabilir veya satır yine başka bir kelimeyi tutabilirken satır sonları oluşabilir.


5
Bu bağlantı kopmuş gibi görünüyor.
zaphod

1
Ve işleri daha da kötüleştirmek için, ilgili sayfayı hiçbir yerde bulamadım.
stricjux


7

Oldukça zarif bir çözüm buldum.

Söylediğiniz gibi, ana belgede bulunan kodu çalıştırmak oldukça kolaydır. Ve bu benim kodumun tabanı, tam tersini yapmak.

İç çerçevem ​​yüklendiğinde, üst belgede bulunan bir işlevi çağırır, bağımsız değişken olarak iframe'in belgesinde bulunan yerel bir işleve başvuru iletir. Ana belgenin artık iframe'in bu referans aracılığıyla işlevine doğrudan erişimi vardır.

Misal:

Ebeveynte:

function tunnel(fn) {
    fn();
}

İframe'de:

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

parent.tunnel(myFunction);

İframe yüklendiğinde, parametrede alınan işlevi yürütecek parent.tunnel (YourFunctionReference) öğesini çağırır.

Bu kadar basit, çeşitli tarayıcıların tüm standart dışı yöntemlerle uğraşmak zorunda kalmadan.


Merhaba, bunu onaylayabilir misin "Bu kadar basit, çeşitli tarayıcıların standart dışı yöntemlerle uğraşmak zorunda kalmadan?"
Milche Patern

1
Bu yöntemi çeşitli projelerde kullanıyorum, çok iyi çalışıyor gibi görünüyor. Tüm tarayıcıları kişisel olarak dolaşımda test etmedim, ancak hiçbir zaman bir hata raporu almadım.
Julien L

Bir çekicilik, IE 11, Chrome ~ 50 gibi çalışır.
Augustas

1
Sanırım bu alanlar arası değil .. Öyle mi?
Tushar Shukla

@TusharShukla Ne yazık ki hayır, değil.
jeff-h

6

Bu yanıtlardan bazıları CORS sorununu ele almaz veya iletişimi mümkün kılmak için kod snippet'lerini nereye yerleştirdiğinizi açıkça göstermez.

İşte somut bir örnek. Üst sayfadaki bir düğmeyi tıklamak istediğimi ve bunun iframe içinde bir şey yapmasını istediğimi varsayalım. İşte böyle yapardım.

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();
}

Diğer yöne gitmek için (iframe dışındaki yöntemi çağırmak için iframe içindeki düğmeyi tıklayın) kod pasajının yaşadığı yeri değiştirin ve bunu değiştirin:

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

buna:

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

4

JoelAnair'in cevabı ile devam etmek :

Daha fazla sağlamlık için aşağıdaki gibi kullanın:

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

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

Cazibe gibi çalışın :)


3

Nitin Bansal'ın cevabı

ve daha da sağlam olması için:

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;
}

ve

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

var frame_win = getIframeWindow(el);

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


2

Aynı şeyler ama biraz daha kolay bir yol olacak iframe içindeki sayfadan üst sayfa nasıl yenilenir . Sayfayı yeniden yüklemek üzere javascript işlevini çağırmak için üst sayfanın işlevini çağırmanız yeterlidir:

window.location.reload();

Veya bunu doğrudan iframe'deki sayfadan yapın:

window.parent.location.reload();

Her ikisi de çalışır.



1

Üst öğe üzerindeki JavaScript işlevini, gölge kutusu veya ışık kutusu gibi başka bir işlev tarafından oluşturulan iframe'den çağırmak istiyorsanız.

windowNesneyi kullanmaya ve üst işlevi çağırmaya çalışmalısınız:

window.parent.targetFunction();

OP'nin diğer yöne gitmeye çalıştığına inanıyorum
CommandZ

-3

Üst sayfadaki çerçevenin işlevini çağırmak için aşağıdakini kullanın

parent.document.getElementById('frameid').contentWindow.somefunction()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.