Appel d'une fonction de fenêtre parent à partir d'un iframe

282

Je veux appeler une fonction JavaScript de la fenêtre parent à partir d'un iframe.

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

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>
Arjun Singh
la source
1
Je ne pourrai rien montrer pour le moment (2016), je ne sais pas si l'ancien tuteur soutiendrait tout
Weijing Jay Lin

Réponses:

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

Voir window.parent

Renvoie une référence au parent de la fenêtre ou du sous-cadre actuel.

Si une fenêtre n'a pas de parent, sa propriété parent est une référence à elle-même.

Lorsqu'une fenêtre est chargé dans un <iframe>, <object>ou <frame>, son parent est la fenêtre avec l'élément d' encastrement de la fenêtre.

rahul
la source
17
Tenez toujours compte du fait que le document parent et le document iframe doivent correspondre par protocole et nom de domaine. Si cela ne se produit pas, vous obtiendrez une erreur de sécurité car il n'est pas autorisé à avoir des scripts interdomaines.
a4bike
Je me demande simplement lequel des deux alertsera invoqué; la alertfonction parent ou la fonction iframe alert, au cas où parent.abc();est appelé iframe?
Prakhar Mishra
@PrakharMishra Ne soyez pas confus. parent signifie parent.
Sahu V Kumar
3
@ a4bike pour de tels scénarios, window.postMessage()(ou window.parent.postMessage()) existe. Vérifiez la réponse @Andrii
Fr0zenFyr
81

J'ai récemment dû découvrir pourquoi cela ne fonctionnait pas aussi.

Le javascript que vous souhaitez appeler de l'iframe enfant doit être dans la tête du parent. S'il se trouve dans le corps, le script n'est pas disponible dans la portée globale.

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

J'espère que cela aidera à nouveau tous ceux qui tomberont sur ce problème.

Ash Clarke
la source
1
Aucune des techniques mentionnées dans ce post ne fonctionne sur Chrome. Des solutions pour cela?
Kumar Kush du
3
Si je me souviens bien, je ne pouvais pas faire fonctionner cela comme prévu si l'iframe avait un domaine différent du parent. Désolé, ce n'est pas une solution, mais cela pourrait expliquer pourquoi cela ne fonctionne pas.
Ash Clarke
1
Oui. Je sais que c'est à cause de différents domaines, mais n'y a-t-il pas moyen de contourner cela?
Kumar Kush
1
Je viens de publier ce qui pourrait être une solution à votre problème. Jetez un œil à l'autre réponse.
Ash Clarke
1
Selon les mêmes règles de détermination de la politique d'origine (voir: en.wikipedia.org/wiki/… ), les sous-domaines sont considérés comme un nom d'hôte différent d'un sous-domaine d'un domaine. Si vous ne l'avez pas déjà fait, vous pouvez simplement définir document.domain sur le sous-domaine?
Ash Clarke
73

Window.postMessage ()

Cette méthode permet en toute sécurité la cross-origincommunication.

Et si vous avez accès au code de la page parent, toute méthode parent peut être appelée ainsi que toutes les données peuvent être transmises directement à partir de Iframe. Voici un petit exemple:

Page parente:

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

Code iframe:

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

MISES À JOUR:

Note de sécurité:

Fournissez toujours un targetOrigin spécifique, NON *, si vous savez où le document de l'autre fenêtre doit être situé. Le fait de ne pas fournir une cible spécifique divulgue les données que vous envoyez à tout site malveillant intéressé (commentaire de ZalemCitizen ).

Références:

Andrii Verbytskyi
la source
1
Je préfère utiliser cela aux autres. Surtout parce qu'il est plus logique d'utiliser des iframes sur des documents d'origine croisée (bien que les programmeurs exploitent les iframes plus souvent qu'autrement) et étant donné le large soutien de cette fonction sur les navigateurs.
Fr0zenFyr
1
Merci! Je dois toujours passer une heure ou plus à revenir en arrière et à rechercher comment faire la messagerie avec des exemples compliqués et verbeux. Cela a fonctionné en 60 secondes. Merci pour un exemple succinct et précis.
RandallTo
2
vaut la peine de soulever cela (à partir des documents Web MDN ): Fournissez toujours un targetOrigin spécifique, pas *, si vous savez où le document de l'autre fenêtre doit être situé. Ne pas fournir une cible spécifique divulgue les données que vous envoyez à tout site malveillant intéressé
ZalemCitizen
20

J'ai posté cela comme une réponse distincte car elle n'est pas liée à ma réponse existante.

Ce problème s'est récemment reproduit pour accéder à un parent à partir d'une iframe référençant un sous-domaine et les correctifs existants n'ont pas fonctionné.

Cette fois, la réponse a été de modifier le document.domain de la page parent et l'iframe pour qu'ils soient identiques. Cela trompera les mêmes vérifications de politique d'origine en leur faisant croire qu'elles coexistent exactement sur le même domaine (les sous-domaines sont considérés comme un hôte différent et échouent au même contrôle de politique d'origine).

Insérez ce qui suit dans le <head> page de l'iframe pour correspondre au domaine parent (ajustez votre doctype).

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

Veuillez noter que cela générera une erreur sur le développement localhost, utilisez donc une vérification comme celle-ci pour éviter l'erreur:

if (!window.location.href.match(/localhost/gi)) {
    document.domain = "mydomain.com";
} 
Ash Clarke
la source
et qu'en est-il de tester cela dans localhost? une solution pour cela?
Umesh Awasthi
Voir: "Veuillez noter que cela générera une erreur sur le développement localhost, alors utilisez une vérification comme celle-ci pour éviter l'erreur"
Ash Clarke
2
Il convient de noter que (au moins dans Google Chrome), le parent et l'enfant DOIVENT DÉFINIR document.domain même si l'un d'eux est déjà "correct"! Exemple: le parent est example.comiframe abc.example.com, alors le parent et iframe doivent appelerdocument.domain = "example.com"
KillerX
Oui c'est correct, j'ai fait une faute de frappe ici: "la page dans l'iframe doit être la même." doit être "page et iframe identiques." ..... Merci!
Ash Clarke
pour le if () pourquoi ne pas utiliser if (document.domain! = "mydomain.com"? De plus, je suis confus, le <script> va-t-il dans la fenêtre parente ou l'iFrame? document.domain dans iFrame génère «Impossible de définir la propriété« domaine »sur« Document »:« localhost »n'est pas un suffixe de« sc-localhost ».
user2568374
18

Vous pouvez utiliser

window.top

voir ce qui suit.

<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
la source
Lorsque vous essayez d'appeler parent.custom_function (); à partir d'un iframe ne fonctionne pas, vous pouvez trouver window.top.custom_function (); marchera. Fonctionne pour moi pour une raison étrange. Mes javascripts sur la fenêtre parent sont tous intégrés dans le pied de page, j'ai lu quelque part que l'inclusion de fichiers javascript dans le pied de page provoque le problème parent.custom_function () ne fonctionne pas.
Friso Horstman
@Vinothkumar, une question s'il vous plaît, quelle est la différence entre appeler "window.top.abc ()" et appeler uniquement "abc ()", merci d'avance =)
Zilev av
@Zilev av Le point entier de ce fil appelle une fonction dans un document parent à partir d'un iframe enfant. Voilà la différence. L'appel abc()ne fonctionnerait que s'il function abc()était déclaré dans l'iframe plutôt que sur la page parent. window.top.abc()éclate de l'iframe dans le document parent.
Sean Kendle
3

Un autre ajout pour ceux qui en ont besoin. La solution d'Ash Clarke ne fonctionne pas s'ils utilisent des protocoles différents, alors assurez-vous que si vous utilisez SSL, votre iframe utilise également SSL ou cela cassera la fonction. Sa solution a bien fonctionné pour les domaines lui-même, alors merci pour cela.

Devon
la source
2

La solution proposée par Ash Clarke pour les sous-domaines fonctionne très bien, mais veuillez noter que vous devez inclure le document.domain = "mydomain.com"; à la fois en tête de la page iframe et en tête de la page parent, comme indiqué dans le lien même vérification des règles d'origine

Une extension importante de la même politique d'origine mise en œuvre pour l'accès DOM JavaScript (mais pas pour la plupart des autres versions de vérifications de même origine) est que deux sites partageant un domaine de premier niveau commun peuvent choisir de communiquer malgré l'échec du "même hôte". vérifier en définissant mutuellement leur propriété DOM document.domain respective sur le même fragment qualifié de droite de leur nom d'hôte actuel. Par exemple, si http://en.example.com/ et http://fr.example.com/ définissent tous deux document.domain sur "example.com", ils seraient à partir de ce moment considérés comme de même origine pour le but de la manipulation DOM.

Frato
la source
Oui c'est correct, j'ai fait une faute de frappe ici: "la page dans l'iframe doit être la même." doit être "page et iframe identiques." ..... Merci!
Ash Clarke
que diriez-vous d'exécuter des fichiers sur l'ordinateur local? quelle est la valeur de document.domain?
Raptor
Ce sera localhostou l'adresse IP de la machine (généralement 127.0.0.1), selon ce qui est dans la barre d'adresse URL.
Ash Clarke
2

parent.abc () ne fonctionnera que sur le même domaine pour des raisons de sécurité. j'ai essayé cette solution de contournement et la mienne a parfaitement fonctionné.

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

J'espère que cela t'aides. :)

Seph Remotigue
la source
Cela n'est également vraiment utile que pour le document iframe, ce qui ajoute d'énormes complications si vous devez vous référer aux contrôles du formulaire parent.
Paul
1

Avec Firefox et Chrome, vous pouvez utiliser:

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

Si ma fonction est présente à la fois dans iframe et dans parent, la fonction parent sera appelée.

flocon de neige
la source
ça ne marche pas. Voici ma démo: dotku.github.io/tech/html/iframe/iframe_function_container.html
Weijing Jay Lin
Comme indiqué par Ash Clarke, le javascript que vous souhaitez appeler de l'enfant iframe doit être dans la tête du parent.
flocon de neige
La réponse acceptée n'a pas besoin que le script soit dans la tête. Je n'ai pas testé si cette solution n'avait plus besoin que le script soit dans la tête ou non.
Guy Schalnat
0

Bien que certaines de ces solutions puissent fonctionner, aucune ne respecte les meilleures pratiques. Beaucoup affectent des variables globales et vous pouvez vous retrouver à appeler plusieurs variables ou fonctions parentes, conduisant à un espace de noms encombré et vulnérable.

Pour éviter cela, utilisez un modèle de module. Dans la fenêtre parent:

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

var newThing = Object.create(myThing);

Ensuite, dans l'iframe:

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

Ceci est similaire aux modèles décrits dans le chapitre Héritage du texte fondateur de Crockford, «Javascript: The Good Parts». Vous pouvez également en savoir plus sur la page de w3 pour les meilleures pratiques de Javascript. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

William J. Littlefield
la source