Chamando uma função de janela pai de um iframe

281

Quero chamar uma função JavaScript da janela pai de um iframe.

<script>
    function abc()
    {
        alert("sss");
    }
</script>

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>
Arjun Singh
fonte
1
Não vou conseguir mostrar nada agora (2016), não sei se o caramanchão mais velho suportaria algum #
Weijing Jay Lin 21/16

Respostas:

438
<a onclick="parent.abc();" href="#" >Call Me </a>

Consulte window.parent

Retorna uma referência ao pai da janela ou subquadro atual.

Se uma janela não tiver um pai, sua propriedade pai será uma referência a si mesma.

Quando uma janela é carregado em um <iframe>, <object>ou <frame>, o seu pai é a janela com o elemento de incorporação da janela.

rahul
fonte
17
Sempre leve em consideração que o documento pai e o iframe devem corresponder por protocolo e nome de domínio. Se isso não acontecer, você receberá um erro de segurança, pois não é permitido o uso de scripts entre domínios.
a4bike 02/09
Estou apenas imaginando qual dos dois alertserá invocado; alertfunção dos pais ou função iframe alert, caso parent.abc();seja chamada em iframe?
Prakhar Mishra 03/03
@PrakharMishra Não fique confuso. pai significa pai.
Sahu V Kumar
3
@ a4bike para esses cenários, window.postMessage()(ou window.parent.postMessage()) existe. Verifique @Andrii resposta
Fr0zenFyr 6/17
81

Recentemente, tive que descobrir por que isso também não funcionou.

O javascript que você deseja chamar do iframe filho precisa estar na cabeça dos pais. Se estiver no corpo, o script não estará disponível no escopo global.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="parent.abc();" href="#">Click Me</a>
    </iframe>
</body>

Espero que isso ajude qualquer pessoa que se deparar com esse problema novamente.

Ash Clarke
fonte
1
Nenhuma das técnicas mencionadas nesta postagem funciona no Chrome. Alguma solução para isso?
precisa saber é o seguinte
3
Se bem me lembro, não poderia fazer isso funcionar como esperado se o iframe tivesse um domínio diferente do pai. Desculpe, isso não é uma solução, mas pode explicar por que não está funcionando.
Ash Clarke
1
Sim. Eu sei que é por causa de domínios diferentes, mas não há uma maneira de contornar isso?
Kumar Kush
1
Acabei de publicar o que pode ser uma solução alternativa para o seu problema. Dê uma olhada na outra resposta.
Ash Clarke
1
De acordo com as mesmas regras de determinação da política de origem (consulte: en.wikipedia.org/wiki/… ), os subdomínios são considerados um nome de host diferente de um subdomínio de um domínio. Se você ainda não o fez, tente definir apenas document.domain como subdomínio?
Ash Clarke
72

Window.postMessage ()

Este método habilita a cross-origincomunicação com segurança .

E se você tiver acesso ao código da página pai, qualquer método pai poderá ser chamado, assim como qualquer dado transmitido diretamente Iframe. Aqui está um pequeno exemplo:

Página principal:

if (window.addEventListener) {
    window.addEventListener("message", onMessage, false);        
} 
else if (window.attachEvent) {
    window.attachEvent("onmessage", onMessage, false);
}

function onMessage(event) {
    // Check sender origin to be trusted
    if (event.origin !== "http://example.com") return;

    var data = event.data;

    if (typeof(window[data.func]) == "function") {
        window[data.func].call(null, data.message);
    }
}

// Function to be called from iframe
function parentFunc(message) {
    alert(message);
}

Código Iframe:

window.parent.postMessage({
    'func': 'parentFunc',
    'message': 'Message text from iframe.'
}, "*");
// Use target origin instead of *

ATUALIZAÇÕES:

Nota de segurança:

Sempre forneça um targetOrigin específico, NÃO *, se você souber onde o documento da outra janela deve estar localizado. Não fornecer um destino específico divulga os dados que você envia para qualquer site malicioso interessado (comentário da ZalemCitizen ).

Referências:

Andrii Verbytskyi
fonte
1
Eu prefiro usar isso do que outros. Especialmente porque faz mais sentido usar iframes em documentos de origem cruzada (embora os programadores explorem iframes com mais frequência do que não) e devido ao amplo suporte para essa função nos navegadores.
Fr0zenFyr
1
Obrigado! Eu sempre tenho que gastar uma hora ou mais voltando e pesquisando como fazer as mensagens com exemplos detalhados e complicados. Isso funcionou em 60 segundos. Obrigado por um exemplo sucinto e direto ao ponto.
usar o seguinte comando
2
vale a pena enfatizar isso (nos documentos da web da MDN ): sempre forneça um targetOrigin específico, não *, se você souber onde o documento da outra janela deve estar localizado. Não fornecer um alvo específico divulga os dados que você enviar para qualquer site malicioso interessados
ZalemCitizen
20

Publiquei isso como uma resposta separada, pois não está relacionado à minha resposta existente.

Esse problema surgiu recentemente para acessar um pai de um iframe que faz referência a um subdomínio e as correções existentes não funcionaram.

Dessa vez, a resposta foi modificar o documento.domínio da página pai e o iframe para ser o mesmo. Isso fará com que as mesmas verificações de política de origem pensem que coexistem exatamente no mesmo domínio (subdomínios são considerados um host diferente e falham na mesma verificação de política de origem).

Insira o seguinte <head>na página no iframe para corresponder ao domínio pai (ajuste para o seu tipo de documento).

<script>
    document.domain = "mydomain.com";
</script>

Observe que isso gerará um erro no desenvolvimento do host local, portanto, use uma verificação como a seguinte para evitar o erro:

if (!window.location.href.match(/localhost/gi)) {
    document.domain = "mydomain.com";
} 
Ash Clarke
fonte
e quanto a testar isso no localhost? alguma solução alternativa para isso?
Umesh Awasthi
Veja: "Observe que isso gerará um erro no desenvolvimento do host local, portanto, use uma verificação como a seguinte para evitar o erro"
Ash Clarke
2
Vale a pena notar que (pelo menos no Google Chrome), pai e filho DEVEM CONFIGURAR document.domain mesmo se um deles já estiver "correto"! Exemplo: Pai é example.comiframe é abc.example.com, em seguida, o pai ea iframe deve chamardocument.domain = "example.com"
KillerX
Sim, está correto, cometi um erro de digitação aqui: "a página no iframe deve ser a mesma". deve ser "página e o iframe iguais". ..... Obrigado!
Ash Clarke
Para o if (), por que você não usaria if (document.domain! = "mydomain.com"? Além disso, estou confuso, o <script> aparece na janela pai ou no iFrame? document.domain no iFrame gera "Falha ao definir a propriedade 'domínio' no 'Documento': 'localhost' não é um sufixo de 'sc-localhost'.
user2568374
18

Você pode usar

window.top

veja o seguinte.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="window.top.abc();" href="#">Click Me</a>
    </iframe>
</body>
Vinothkumar Arputharaj
fonte
Ao tentar chamar parent.custom_function (); de um iframe não funciona, você pode encontrar window.top.custom_function (); vai funcionar. Funciona para mim por algum motivo estranho. Meus javascripts na janela pai estão todos incorporados no rodapé, li em algum lugar que a inclusão de arquivos javascript no rodapé causa o problema parent.custom_function () não está funcionando.
Friso Horstman
@Vinothkumar, uma pergunta, por favor, que é a diferença entre chamar "window.top.abc ()" do que chamar apenas "abc ()", obrigado antecipadamente =)
Zilev av
@Zilev av O ponto inteiro deste thread está chamando uma função em um documento pai de um iframe filho. Essa é a diferença. A chamada abc()só funcionaria se function abc()fosse declarada no iframe e não na página pai. window.top.abc()quebra o iframe no documento pai.
Sean Kendle
3

Outra adição para quem precisa. A solução da Ash Clarke não funciona se eles estiverem usando protocolos diferentes, portanto, se você estiver usando SSL, seu iframe também está usando SSL ou isso interromperá a função. Sua solução funcionou para os domínios em si, então obrigado por isso.

Devon
fonte
2

A solução dada por Ash Clarke para subdomínios funciona muito bem, mas observe que você precisa incluir o documento.domínio = "meudomínio.com"; no cabeçalho da página iframe e no cabeçalho da página pai, conforme indicado no link verificações de política de mesma origem

Uma extensão importante da mesma política de origem implementada para o acesso DOM do JavaScript (mas não para a maioria dos outros tipos de verificações da mesma origem) é que dois sites que compartilham um domínio de nível superior comum podem optar por se comunicar, apesar de falharem no "mesmo host" verifique definindo mutuamente sua respectiva propriedade DOM document.domain para o mesmo fragmento qualificado e à direita do nome do host atual. Por exemplo, se http://en.example.com/ e http://fr.example.com/ definem document.domain como "example.com", eles seriam a partir desse ponto considerados de mesma origem para o finalidade da manipulação do DOM.

Frato
fonte
Sim, está correto, cometi um erro de digitação aqui: "a página no iframe deve ser a mesma". deve ser "página e o iframe iguais". ..... Obrigado!
Ash Clarke
que tal executar arquivos no computador local? qual é o valor de document.domain?
Raptor
Será localhostou o endereço IP da máquina (normalmente 127.0.0.1), dependendo do que estiver na barra de endereço da URL.
Ash Clarke
2

parent.abc () funcionará apenas no mesmo domínio por motivos de segurança. Eu tentei essa solução alternativa e a minha funcionou perfeitamente.

<head>
    <script>
    function abc() {
        alert("sss");
    }

    // window of the iframe
    var innerWindow = document.getElementById('myFrame').contentWindow;
    innerWindow.abc= abc;

    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="abc();" href="#">Click Me</a>
    </iframe>
</body>

Espero que isto ajude. :)

Remoção de Seph
fonte
Isso também é realmente útil para o documento do iframe, adicionando complicações massivas se você precisar consultar os controles no formulário pai.
Paul
1

Com o Firefox e o Chrome, você pode usar:

<a href="whatever" target="_parent" onclick="myfunction()">

Se minha função estiver presente no iframe e no pai, o pai será chamado.

floco de neve
fonte
isso não funciona. Aqui está minha demonstração: dotku.github.io/tech/html/iframe/iframe_function_container.html
Jay Lin
Conforme declarado por Ash Clarke, o javascript que você deseja chamar do iframe filho precisa estar na cabeça dos pais.
Floco de neve
A resposta aceita não precisa que o script esteja na cabeça. Não testei se essa solução também não precisa mais do script estar na cabeça ou não.
Guy Schalnat
0

Embora algumas dessas soluções possam funcionar, nenhuma delas segue as práticas recomendadas. Muitos atribuem variáveis ​​globais e você pode fazer chamadas para várias variáveis ​​ou funções pai, levando a um espaço para nome vulnerável e desordenado.

Para evitar isso, use um padrão de módulo. Na janela principal:

var myThing = {
    var i = 0;
    myFunction : function () {
        // do something
    }
};

var newThing = Object.create(myThing);

Então, no iframe:

function myIframeFunction () {
    parent.myThing.myFunction();
    alert(parent.myThing.i);
};

Isso é semelhante aos padrões descritos no capítulo Herança do texto seminal de Crockford, "Javascript: The Good Parts". Você também pode aprender mais na página da w3 sobre as melhores práticas de Javascript. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

William J. Littlefield
fonte