Come si sa, le attuali impostazioni del
browser, per motivi di sicurezza, limitano le possibilità di comunicazione tra una pagina
HTML e un
iframe contenuto nella stessa.
Per superare questo problema si può ricorrere alla
API JavaScript window.postMessage.
Questo metodo permette di inviare dei
messaggi tra le pagine, che possono essere catturati (window.addEventListener) tramite l'evento
message.
Nell'esempio seguente si considera di avere la pagina principale che risponde all'indirizzo
http://localhost:8080 e la pagina contenuta nell'iframe risponde a
http://localhost:3000, quindi su un
dominio differente.
Pagina principale
La pagina
principale è questa:
<html>
<body>
<h1>Pagina principale</h1>
<div id="messaggio">...</div>
<iframe src="http://localhost:3000/iframe-page.html" style="width: 80%; height: 250px;"></iframe>
<script>
window.addEventListener("message", function (event) {
if (event.origin != 'http://127.0.0.1:3000' && event.origin != 'http://localhost:3000') {
// se arriva da un domino che non conosco ignoro il messaggio
console.error("messaggio ignorato");
return;
}
// event.data contiene il messaggio, una "stringa"
console.log("received from iframe: " + event.data);
// converto il messaggio in un oggetto
const msg = JSON.parse(event.data);
// lo visualizzo su questa pagina (principale)
document.getElementById("messaggio").innerHTML = msg.title + ": " + msg.actualTime;
// rimando un altro messaggio
const newMsg = { value: "Msg di ritorno: " + msg.actualTime };
event.source.postMessage(JSON.stringify(newMsg));
});
</script>
<p>
<a
href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage">Window.postMessage()</a>
</p>
</body>
</html>
la pagina riceve i messaggi inviati dall'iframe tramite
window.addEventListener("message", fn) e a sua volta
reinvia il messaggio all'iframe tramite
event.source.postMessage(msg);.
Da notare che la comunicazione può avvenire sia dall'iframe verso la pagina sia dalla pagina verso l'iframe.
IFrame
L'
HTML dell
'iframe è questo
<html>
<body>
<h2>Pagina Iframe</h2>
<div id="messaggio-locale">...</div>
<hr>
<div id="messaggio-ritorno">...</div>
<script>
setInterval(() => {
const dt = Date();
// il messaggio deve essere stringa, se è un oggetto va poi serializzato
var msg = { title: "test invio messaggi", actualTime: dt };
// visualizzo la data e ora sulla pagina locale
document.getElementById("messaggio-locale").innerHTML = dt;
// serializzo il messaggio e lo invio
window.parent.postMessage(JSON.stringify(msg), "*");
}, 1000);
// gestione messaggio che arriva dalla pagina principale
window.addEventListener("message", function (event) {
console.log('origin', event.origin)
if (event.origin != 'http://127.0.0.1:8080' && event.origin != 'http://localhost:8080'
// se rimando il messaggio l'origin è se stesso
&& event.origin != 'http://127.0.0.1:3000' && event.origin != 'http://localhost:3000'
) {
// se arriva da un domino che non conosco ignoro il messaggio
//console.error("messaggio ignorato");
return;
}
// event.data contiene il messaggio, una "stringa"
console.log("received from main page: " + event.data);
// converto il messaggio in un oggetto
const msg = JSON.parse(event.data);
// lo visualizzo su questa pagina (iframe)
document.getElementById("messaggio-ritorno").innerHTML = msg.value;
});
</script>
</body>
</html>
dove tramite un timer
JavaScript, ogni secondo, viene inviato un messaggio al
parent tramite
window.parent.postMessage(msg) ovvero la pagina principale.
Il messaggio è un oggetto serializzato in
JSON.
Da notare che in entrambi i casi viene verificata la sorgente (URL) del messaggio prima di accettarlo.
Esecuzione
Per eseguire la demo creare i due file
HTML e il seguente file
start.bat nella stessa cartella ed eseguirlo
start http-server.cmd -p 3000 -o iframe-page.html
http-server.cmd -p 8080 -o index.html
Per funzionare richiede l'installazione di
Node JS e del comando
http-server tramite
npm install --global http-server
Note
Questa tecnica di comunicazione tra pagina e iframe, è spesso usata nelle pagine
responsive per permettere all'iframe, di ridimensionarsi in
altezza in funzione della larghezza della pagina e/o del dispositivo, in modo da non avere
scrollbar doppie.
In questo specifico caso il messaggio scambiato sono le dimensioni della finestra che il ricevente userà per adeguare l'altezza.
Per un esempio di utilizzo vedi
iframe-resizer.