Problem bei der Auswahl des Elements in einem Iframe-Buchungsformular

8

Ich versuche, das E-Mail-Feld in diesem Iframe-Buchungsformular auszuwählen. Ich möchte irgendwann etwas anderes mit dem Feld machen, aber als Test möchte ich nur das Element auswählen und den Platzhalter ändern.

Dieser Fehler wird angezeigt, sodass ich ihn nicht richtig auswähle: Nicht erfasst TypeError: Die Eigenschaft 'placeholder' von null in HTMLButtonElement.changeCopy kann nicht festgelegt werden

Sie können hier eine Live-Version meines Codes anzeigen und den Fehler in der Konsole sehen, wenn Sie auf die Schaltfläche oben klicken: https://finnpegler.github.io/cart_recover/

Ich habe den Code auch als Snippet unten eingefügt, aber es wird ein anderer Fehler ausgegeben, der mit Cross-Origin-Frames zu tun hat.

var iframe = document.getElementById("booking-widget-iframe");
var field = iframe.contentWindow.document.querySelector("booking[email]");

function changeCopy() {
field.placeholder = "hello";
}

document.getElementById("button").addEventListener("click", changeCopy)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test site for Cart Recover Tool</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" media="screen" href="stylesheet.css" />
<link href="https://fonts.googleapis.com/css?family=Bree+Serif|Open+Sans&display=swap" rel="stylesheet">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">  
</head>
<body>
Clicking this button should change the placeholder text in the email field below
<button id = "button">Click</button>
</body>

<script src="https://bettercleans.launch27.com/jsbundle"></script><iframe id="booking-widget-iframe" src="https://bettercleans.launch27.com/?w_cleaning" style="border:none;width:100%;min-height:2739px;overflow:hidden" scrolling="no"></iframe>
<script src="script.js"></script>

FinnPegler
quelle
1
Browser blockieren Versuche eines übergeordneten Frames, den Inhalt oder die Struktur eines untergeordneten Frames zu manipulieren, wenn sie nicht denselben Ursprung haben, dh nicht dieselbe Domäne. In Ihrem Fall ist der Ursprung des übergeordneten Frames finnpegler.github.io, aber der Ursprung des untergeordneten Frames ist bettercleans.launch27.com. Wenn Sie Zugriff auf den Quellcode von js von bettercleans.launch27.com haben, können Sie versuchen, dies zu umgehen, indem Sie eine Nachricht an den untergeordneten Frame senden. Sehen Sie, ob dieser SO-Beitrag Ihnen hilft, stackoverflow.com/questions/25098021/…
Nivi M

Antworten:

6

Der Grund, warum das Feld null ist, liegt darin, dass der Wert blockiert wurde, als die Variable festgelegt wurde. Versuchen Sie, Ihre JavaScript-Konsole auf der Seite zu öffnen und einzufügen

var iframe = document.getElementById("booking-widget-iframe");

Wie in der Quelle, die funktionieren sollte, aber dann sehen, was passiert, wenn Sie eingeben:

var field = iframe.contentWindow.document.querySelector("booking[email]");

Sie sollten so etwas wie den folgenden Fehler erhalten:

Uncaught DOMException: Blocked a frame with origin "https://finnpegler.github.io" from accessing a cross-origin frame.
    at <anonymous>:1:34

Das Problem besteht also nicht darin field.placeholder = "hello";, null zu sein, sondern darin, dass das Feld nie festgelegt wurde, weil es von einer Quelle mit unterschiedlichem Ursprung blockiert wurde.

So beheben Sie das Problem: Wenn Sie Zugriff auf https://bettercleans.launch27.com/?w_cleaning&iframe_id=j8szoz0b4 haben , geben Sie irgendwo auf der Quelle dieser Seite das folgende Skript ein:

<script>
addEventListener("message", function(e) {
    console.log(e.data);
    if(e.data["setIt"]) {
        document.querySelector("booking[email]").placeholder = e.data["setIt"];
         e.source.postMessage({
             hi:"I did it" 
         });
    }

});


</script>

Geben Sie dann auf Ihrer https://finnpegler.github.io/cart_recover/ Seitenquelle irgendwo den Code ein:

<script>
var iframe;
addEventListener("load", function() {
    iframe = document.getElementById("booking-widget-iframe");
    iframe.contentWindow.postMessage({
        setIt: "hello"
    });

});
addEventListener("message", function(e) {
    console.log(e);
})
</script>

Warnung: Ungetesteter Code, aber hier ist die Grundidee: Mit clientseitigem JavaScript können Sie die Elemente eines Iframes nicht direkt bearbeiten. Um mit ihm zu kommunizieren, senden Sie eine Nachricht mit iframe.contentWindow.postMessage an den Iframe. Auf der Iframe-Seite können Sie die Nachricht lesen, die mit der Ereignisnachricht "message" eingeht (oder Sie können window.onmessage ausführen). Anschließend können Sie JSON-Daten oder -Text als Nachricht an den Iframe senden und mit e.data lesen. Wenn im obigen (nicht getesteten) Beispiel die Haupt-Github-Seite den Wert des Platzhalters auf einen bestimmten Betrag ändern möchte, sendet sie einfach ein JSON-Objekt, das die Platzhalterdaten enthält, an den Iframe und dann auf der Iframe-Quellseite liest diese eingehende Nachricht, prüft den JSON, ob er den gesetzten Schlüssel zum Setzen des Platzhalters hat, und ob er diesen Schlüssel hat,

Lassen Sie mich wissen, wenn Sie weitere Fragen haben.

Hier einige Referenzen:

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage https://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage https://javascript.info/ fensterübergreifende Kommunikation https://bl.ocks.org/pbojinov/8965299 https://www.ilearnjavascript.com/plainjs-postmessage-and-iframes/ https://medium.com/@Farzad_YZ/cross-domain -iframe-parent-Communication-403912fff692

Bluejayke
quelle
0

Lassen Sie uns zunächst etwas Klarheit darüber bringen, was wirklich passiert. Um die Analyse zu erleichtern, habe ich Ihr Skript wie folgt geändert, ohne Nebenwirkungen hervorzurufen:

var iframe = document.getElementById( "booking-widget-iframe" );

console.log( `iframe: ${ iframe }` );
console.log( `iframe.contentWindow: ${ iframe.contentWindow }` );
console.log( `iframe.contentWindow.document: ${ iframe.contentWindow.document }` );
console.log( `iframe.contentWindow.document.querySelector("booking[email]"): ${ iframe.contentWindow.document.querySelector( "booking[email]" ) }` );

function changeCopy() {
    console.log( "-------------------------------------------------------------------------------" );
    console.log( "changeCopy: started" );
    console.log( "-------------------------------------------------------------------------------" );

    var iframe = document.getElementById( "booking-widget-iframe" );

    console.log( `iframe: ${ iframe }` );
    console.log( `iframe.contentWindow: ${ iframe.contentWindow }` );
    console.log( `iframe.contentWindow.document: ${ iframe.contentWindow.document }` );
    console.log( `iframe.contentWindow.document.querySelector("booking[email]"): ${ iframe.contentWindow.document.querySelector( "booking[email]" ) }` );

    var field = iframe.contentWindow.document.querySelector( "booking[email]" );
    field.placeholder = "hello";

    console.log( "-------------------------------------------------------------------------------" );
    console.log( "changeCopy: finished" );
    console.log( "-------------------------------------------------------------------------------" );
}

document.getElementById( "button" ).addEventListener( "click", changeCopy )

Das Laden des Dokuments mit dem obigen Skript ergab das folgende Ergebnis: Führen Sie die Skriptausgabe aus

Was haben wir aus der Ausgabe gelernt?

  1. Bevor auf die Schaltfläche geklickt wurde, wird iframe.contentWindow.document.querySelector( "booking[email]" )ausgewertet null. Daher war die Variable fieldim Wesentlichen null.

  2. Warum wurde vor dem Klickeniframe.contentWindow.document.querySelector( "booking[email]" ) auf null die Schaltfläche ausgewertet ?

    • Da das iframeDokument nicht geladen wurde, hielt es der Browser (Safari) für suboptimal, Sicherheitsrichtlinien zwischen dem übergeordneten und dem untergeordneten Frame auszuführen.
  3. Als ich auf die Schaltfläche " Klicken" drückte , war der documentvon #booking-widget-iframe(untergeordneter Frame) vollständig geladen, und die Durchsetzung von Sicherheitsrichtlinien zwischen dem übergeordneten und dem untergeordneten Frame wurde aktiviert. Infolgedessen wurde der Zugriffsversuch iframe.contentWindowsofort blockiert, da die Richtlinien für den Cross-Origin-Frame nicht eingehalten wurden.

Mögliche Auflösungen:

  • Damit Skripten im übergeordneten Frame Zugriff auf Objekte im untergeordneten Frame erhalten, sollten sowohl übergeordnete als auch untergeordnete Frames von demselben domain(dh https://bettercleans.launch27.com ) und port(für den betreffenden Fall irrelevant ) geladen werden ).
  • Alternativ können Sie Post-Messaging für die Interaktion zwischen beiden Frames verwenden, wie in Window.postMessage () dokumentiert .

Angenommen, Sie könnten die Lösung anwenden, sollte ein weiteres Problem auftreten 🙂. iframe.contentWindow.document.querySelector("booking[email]")wäre noch null. Die Hauptursache für das nachfolgende Problem wäre, dass im Zieldokument kein benanntes Element bookinggefunden werden konnte. Mit anderen Worten, der Selektor "booking[email]"ist fehlerhaft.

Igwe Kalu
quelle