jQuery / JavaScript: accesso ai contenuti di un iframe


792

Vorrei manipolare l'HTML all'interno di un iframe usando jQuery.

Ho pensato di poterlo fare impostando il contesto della funzione jQuery come documento dell'iframe, qualcosa del tipo:

$(function(){ //document ready
    $('some selector', frames['nameOfMyIframe'].document).doStuff()
});

Tuttavia, questo non sembra funzionare. Un po 'di ispezione mi mostra che le variabili frames['nameOfMyIframe']sono a undefinedmeno che non aspetto un po' di tempo per caricare l'iframe. Tuttavia, quando l'iframe carica le variabili non sono accessibili (ottengo permission deniederrori di tipo).

Qualcuno sa di una soluzione a questo?


3
Cosa contiene l'iFrame: il suo src è impostato su un altro dominio?
James,

se si tratta di un altro dominio, c'è ancora un modo per accedere al suo contenuto o registrare un evento
adardesign,

34
No, perché sarebbe uno scripting cross-site, che è proibito per motivi di sicurezza. La mia soluzione era quella di utilizzare un proxy: alimentare l'HTML in modo dettagliato IFRAME attraverso il mio sito in modo che non sia più cross-site dal punto di vista del browser.
reinierpost,

E 'più cross-browser da usare .contentWindow.documentrispetto .documental iframeelemento. Suggerirò la modifica sopra.
Alan H.

1
un modo è estensioni di Chrome
Muhammad Umer

Risposte:


384

Penso che ciò che stai facendo sia soggetto alla stessa politica di origine . Questo dovrebbe essere il motivo per cui stai ricevendo errori di tipo negato permesso .


6
La migliore scommessa di @Pacerier è quella di delegare il contenuto dell'iframe sul tuo sito, se puoi ...
Tracker1

10
@ Tracker1: puoi suggerire qualsiasi modello di framework / api / design per l'implementazione di questa soluzione proxy. Qualche link ad esempio o tutorial ecc? Ho provato a cercare ma non ne ho trovato.
Umer Hayat,

3
In questo caso, intende utilizzare il server http che serve la pagina del tuo dominio come proxy - richiedere il contenuto dal sito di terze parti e inoltrarlo nella risposta http al client. Come probabilmente puoi immaginare, influisce rapidamente sulla reattività del tuo sito poiché richieste parallele precedenti vengono invece eseguite in serie con il tuo server come potenziale collo di bottiglia.
Rutherford,

1
@Pacerier Potenzialmente uno qualsiasi dei metodi nella risposta accettata qui: stackoverflow.com/questions/3076414/… o altri (come utilizzare il proprio dominio come proxy), a seconda di ciò che si desidera ottenere.
Mark Amery,

4
Per la cronaca, ho appena impostato qualcosa di simile: se non vuoi che il risultato sia incredibilmente lento, configura il tuo server web per reindirizzare direttamente le richieste di risorse (CSS / JS / immagini) al sito Web originale, quindi il tuo proxy gestisce solo richieste HTML. Sto navigando su un sito distante sotto localhost in questo momento ed è assolutamente trasparente :)
neemzy

985

Se <iframe>proviene dallo stesso dominio, gli elementi sono facilmente accessibili come

$("#iFrame").contents().find("#someDiv").removeClass("hidden");

Riferimento


157
Conoscere la stessa politica di origine è eccezionale, ma questa è la risposta che fa ciò che l'OP voleva. Perché l'altra risposta è stata scelta come quella giusta?
Jason Swett,

2
Devi usare un proxy per ottenere l'HTML nella tua origine. Ad esempio, johnchapman.name/…
mhenry1384,

7
@JasonSwett, la mia ipotesi è che il problema di OP sia effettivamente il same origin policy, nel qual caso questa risposta non è una soluzione per lui.
ANeves

3
@fizzbuzz Quindi ottieni l'IFrame nello stesso modo in cui otterrai qualsiasi altro contenuto id-less con jQuery: selezioni il tag <IFrame> appropriato con CSS, usando nomi di classe e valori di attributo per restringerlo se necessario.
Auspex,

2
Non esiste un metodo chiamato contenuto per iframe.
Renan,

88

È possibile utilizzare il .contents()metodo di jQuery.

Il .contents()metodo può anche essere utilizzato per ottenere il documento di contenuto di un iframe, se iframe si trova sullo stesso dominio della pagina principale.

$(document).ready(function(){
    $('#frameID').load(function(){
        $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
    });
});

2
ho bisogno di ottenere il contenuto del frame i per non impostare il corpo ..... Quando faccio quanto sopra non funziona sempre restituire il corpo vuoto
George Hanna,

3
@DarkoZ Uhm, in realtà questa risposta è arrivata prima, quindi, se non altro, l'altra risposta è stata la copia
michaelpri,

@DarkoZ: lasciare il commento originale non mi ha fatto vergognare, ma ho perso circa 30 secondi nel tentativo di capire un non-problema :) Quindi rimuovere l'intera discussione su una risposta plagiare potrebbe essere la cosa migliore.
Dan Dascalescu,

commenti rimossi per evitare confusione. scuse.
Darko Z,

43

Se iframe src proviene da un altro dominio, puoi ancora farlo. Devi leggere la pagina esterna in PHP ed eco dal tuo dominio. Come questo:

iframe_page.php

<?php
    $URL = "http://external.com";

    $domain = file_get_contents($URL);

    echo $domain;
?>

Quindi qualcosa del genere:

display_page.html

<html>
<head>
  <title>Test</title>
 </head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>

<script>

$(document).ready(function(){   
    cleanit = setInterval ( "cleaning()", 500 );
});

function cleaning(){
    if($('#frametest').contents().find('.selector').html() == "somthing"){
        clearInterval(cleanit);
        $('#selector').contents().find('.Link').html('ideate tech');
    }
}

</script>

<body>
<iframe name="frametest" id="frametest" src="http://yourdomain.com/iframe_page.php" ></iframe>
</body>
</html>

Quanto sopra è un esempio di come modificare una pagina esterna tramite un iframe senza accesso negato ecc ...


12
Naturalmente, poiché il tuo server sta ottenendo la pagina remota non il browser dell'utente, nessun cookie verrà inviato alla pagina remota. YMMV.
Mark Fowler,

1
@Mark: puoi facilmente inviare cookie, dati pubblicati, intestazioni HTTP e quant'altro se lo implementi con l'estensione curl. php.net/manual/en/book.curl.php
geon,

2
@geon: ma il browser non invierà i cookie per il dominio straniero al tuo script PHP
ysth

6
@basysmith Sii consapevole: c'è un motivo per cui same origin policyesiste, e la proposta di questa risposta non è immune da essa.
ANeves

1
è illegale in qualche modo farlo?
Tallboy,

32

Trovo in questo modo più pulito:

var $iframe = $("#iframeID").contents();
$iframe.find('selector');

Mi sono salvato il culo - Stavo impazzendo, usando "$ (" # iframe "). Contents (). Find ()" non funzionava per qualche motivo ... lo stesso ha fatto su due righe. Non so perché, ma funziona.
neminem,

30

Uso

iframe.contentWindow.document

invece di

iframe.contentDocument

Bella risposta. Funziona con iFrame in altri domini. L'ho provato nella console su Safari e Firefox.
Aneil Mallavarapu il

12
Credo che funzionerà solo per altri domini se lo stai facendo dalla console. Da uno script, l'accesso non sarà consentito.
yincrash,

Questa dovrebbe essere la risposta accettata. Mi ha salvato la vita e funziona quando l'iframe proviene da un dominio diverso; anche se come detto, solo nella console.
Silkfire,

per me iframe.contentWindow.document non funziona sempre. e quando non lo faccio ho scoperto che $ (elem) .contents (). get (0) lo fa
elewinso

puoi scegliere il "documento radice" nella console del browser. Quando selezioni "top" non funzionerà come accesso incrociato. Se scegli di accedere per conto del documento iframe, ovviamente ti darà accesso. Solo perché non sei un browser, ma il proprietario del browser.
Sergei Kovalenko,

26

Devi collegare un evento al gestore onload di un iframe ed eseguire js lì, in modo da assicurarti che l'iframe abbia terminato il caricamento prima di accedervi.

$().ready(function () {
    $("#iframeID").ready(function () { //The function below executes once the iframe has finished loading
        $('some selector', frames['nameOfMyIframe'].document).doStuff();
    });
};

Quanto sopra risolverà il problema "non ancora caricato", ma per quanto riguarda le autorizzazioni, se si sta caricando una pagina nell'iframe che proviene da un dominio diverso, non sarà possibile accedervi a causa di restrizioni di sicurezza.


questa è una buona idea, in effetti ci stavo provando proprio come hai risposto. Tuttavia, non funziona con l'autorizzazione negata (risolve il fatto che devo aspettare prima di iniziare ad accedere alle cose iframe)
rz.

in realtà ... non importa, sembra che l'attesa sia ancora necessaria anche quando lo si fa.
rz.

La funzione Pronta funziona. Tuttavia, sembra che non aspetti che il contenuto dell'iframe finisca il caricamento - solo per il documento principale anche se invocato sul contenuto dell'iframe stesso. Immagino sia anche a causa della stessa politica di origine.
rz.

3
Un paio di note su questo codice: dovresti usare iframe.contentDocument invece di .document e dovresti usare .load () invece di .ready () per evitare l'attesa. (Non perfetto, ma migliore)
Rodrigo Queiro,

21

Puoi usare window.postMessage per chiamare una funzione tra page e il suo iframe (interdominio o no).

Documentazione

page.html

<!DOCTYPE html>
<html>
<head>
    <title>Page with an iframe</title>
    <meta charset="UTF-8" />
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script>
    var Page = {
        id:'page',
        variable:'This is the page.'
    };

    $(window).on('message', function(e) {
        var event = e.originalEvent;
        if(window.console) {
            console.log(event);
        }
        alert(event.origin + '\n' + event.data);
    });
    function iframeReady(iframe) {
        if(iframe.contentWindow.postMessage) {
            iframe.contentWindow.postMessage('Hello ' + Page.id, '*');
        }
    }
    </script>
</head>
<body>
    <h1>Page with an iframe</h1>
    <iframe src="iframe.html" onload="iframeReady(this);"></iframe>
</body>
</html>

iframe.html

<!DOCTYPE html>
<html>
<head>
    <title>iframe</title>
    <meta charset="UTF-8" />
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script>
    var Page = {
        id:'iframe',
        variable:'The iframe.'
    };

    $(window).on('message', function(e) {
        var event = e.originalEvent;
        if(window.console) {
            console.log(event);
        }
        alert(event.origin + '\n' + event.data);
    });
    $(window).on('load', function() {
        if(window.parent.postMessage) {
            window.parent.postMessage('Hello ' + Page.id, '*');
        }
    });
    </script>
</head>
<body>
    <h1>iframe</h1>
    <p>It's the iframe.</p>
</body>
</html>

4

Preferisco usare un'altra variante per accedere. Da genitore puoi avere accesso alla variabile in iframe figlio. $è anche una variabile e puoi ricevere l'accesso alla sua sola chiamata window.iframe_id.$

Ad esempio, window.view.$('div').hide()- nascondi tutti i div in iframe con id 'view'

Ma non funziona in FF. Per una migliore compatibilità è necessario utilizzare

$('#iframe_id')[0].contentWindow.$


2

Hai provato il classico, aspettando che il caricamento si completasse usando la funzione ready-in integrata di jQuery?

$(document).ready(function() {
    $('some selector', frames['nameOfMyIframe'].document).doStuff()
} );

K


2
Sì. La funzione ready inizia l'esecuzione quando viene caricato il frame principale, non quando viene caricato l'iframe. L'attesa sembra essere una piccola parte del problema, però. Penso che abbia a che fare con la sicurezza tra domini.
rz.

2

Creo un codice di esempio. Ora puoi facilmente capire da un dominio diverso che non puoi accedere al contenuto di iframe. Nello stesso dominio possiamo accedere al contenuto di iframe

Ti condivido il mio codice, esegui questo codice controlla la console. Stampa l'immagine src sulla console. Ci sono quattro iframe, due iframe provenienti dallo stesso dominio e altri due da un altro dominio (di terze parti). Puoi vedere due immagini src ( https://www.google.com/logos/doodles/2015/googles-new-logo -5078286822539264,3-hp2x.gif

e

https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) sulla console e possono anche visualizzare due errori di autorizzazione (2 Errore: autorizzazione negata per accedere al documento "della proprietà" '

... irstChild)}, contents: function (a) {return m.nodeName (a, "iframe")? a.contentDocument ...

) proveniente da iframe di terze parti.

<body id="page-top" data-spy="scroll" data-target=".navbar-fixed-top">
<p>iframe from same domain</p>
  <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="iframe.html" name="imgbox" class="iView">

</iframe>
<p>iframe from same domain</p>
<iframe frameborder="0" scrolling="no" width="500" height="500"
   src="iframe2.html" name="imgbox" class="iView1">

</iframe>
<p>iframe from different  domain</p>
 <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif" name="imgbox" class="iView2">

</iframe>

<p>iframe from different  domain</p>
 <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="http://d1rmo5dfr7fx8e.cloudfront.net/" name="imgbox" class="iView3">

</iframe>

<script type='text/javascript'>


$(document).ready(function(){
    setTimeout(function(){


        var src = $('.iView').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 2000);


    setTimeout(function(){


        var src = $('.iView1').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 3000);


    setTimeout(function(){


        var src = $('.iView2').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 3000);

         setTimeout(function(){


        var src = $('.iView3').contents().find("img").attr('src');
    console.log(src);
         }, 3000);


    })


</script>
</body>

1

Sono finito qui alla ricerca di ottenere il contenuto di un iframe senza jquery, quindi per chiunque lo cerchi, è proprio questo:

document.querySelector('iframe[name=iframename]').contentDocument

1

Questa soluzione funziona come iFrame. Ho creato uno script PHP in grado di ottenere tutti i contenuti dall'altro sito Web e la parte più importante è che puoi facilmente applicare il tuo jQuery personalizzato a quel contenuto esterno. Si prega di fare riferimento al seguente script che può ottenere tutto il contenuto dall'altro sito Web e quindi è possibile applicare anche il proprio jQuery / JS personalizzato. Questo contenuto può essere utilizzato ovunque, all'interno di qualsiasi elemento o pagina.

<div id='myframe'>

  <?php 
   /* 
    Use below function to display final HTML inside this div
   */

   //Display Frame
   echo displayFrame(); 
  ?>

</div>

<?php

/* 
  Function to display frame from another domain 
*/

function displayFrame()
{
  $webUrl = 'http://[external-web-domain.com]/';

  //Get HTML from the URL
  $content = file_get_contents($webUrl);

  //Add custom JS to returned HTML content
  $customJS = "
  <script>

      /* Here I am writing a sample jQuery to hide the navigation menu
         You can write your own jQuery for this content
      */
    //Hide Navigation bar
    jQuery(\".navbar.navbar-default\").hide();

  </script>";

  //Append Custom JS with HTML
  $html = $content . $customJS;

  //Return customized HTML
  return $html;
}

0

Per una resistenza ancora maggiore:

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

e

...
var frame_win = getIframeWindow( frames['nameOfMyIframe'] );

if (frame_win) {
  $(frame_win.contentDocument || frame_win.document).find('some selector').doStuff();
  ...
}
...
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.