iframe予約フォームで要素を選択する際の問題


8

このiframe予約フォームでメールフィールドを選択しようとしています。最終的にはフィールドで別のことをしたいのですが、今のところテストとして、要素を選択してプレースホルダーを変更したいだけです。

このエラーが発生したため、正しく選択していません:Uncaught TypeError:HTMLButtonElement.changeCopyでnullのプロパティ 'placeholder'を設定できません

ここで私のコードのライブバージョンを表示し、上部のボタンをクリックするとコンソールにエラーが表示されます。https//finnpegler.github.io/cart_recover/

以下のスニペットとしてコードも含めましたが、クロスオリジンフレームで行うと別のエラーがスローされます。

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>


1
ブラウザは、同じ起源でない、つまり同じドメインでない場合、親フレームによる子フレームのコンテンツまたは構造の操作の試みをブロックします。あなたの場合、親フレームの原点はfinnpegler.github.ioですが、子フレームの原点はbettercleans.launch27.comです。bettercleans.launch27.comのjsソースコードにアクセスできる場合は、子フレームにメッセージを投稿することで回避できます。このSOの投稿がstackoverflow.com/questions/25098021/…に
Nivi M

回答:


6

フィールドがnullである理由は、変数が設定されたときに値がブロックされたためです。ページでJavaScriptコンソールを開いて貼り付けてみてください

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

ソースのように動作するはずですが、次に入力するとどうなるかを確認してください:

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

次のようなエラーが表示されます。

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

つまり、問題はfield.placeholder = "hello";nullであるということではなく、クロスオリジンソースからブロックされたためにフィールドが設定されなかったことです。

これを修正する方法:https://bettercleans.launch27.com/?w_cleaning&iframe_id=j8szoz0b4にアクセスできる場合、そのページのソースのどこかに、次のスクリプトを入力します。

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

次に、https://finnpegler.github.io/cart_recover/ページのソースのどこかに、コードを入力します。

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

警告:テストされていないコードですが、基本的な考え方は次のとおりです。クライアント側のJavaScriptでは、iframeの要素を直接編集できないため、それと通信する方法は、iframe.contentWindow.postMessageを使用してiframeにメッセージを送信することです。iframe側では、イベントリスナー "message"で着信するメッセージを読み取ることができます(またはwindow.onmessageを実行できます)。次に、JSONデータまたはテキストをメッセージとしてiframeに送信し、e.dataで読み取ることができます。したがって、上記の(テストされていない)例では、メインgithubページがプレースホルダーの値を特定の量に変更する必要がある場合、プレースホルダーデータを含むJSONオブジェクトをiframeに送信し、iframeソース側では、その着信メッセージを読み取り、プレースホルダーを設定するための設定キーがある場合はJSONをチェックし、そのキーがある場合は、

他にご不明な点がありましたらお知らせください。

ここにいくつかの参照があります:

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage https://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage https://javascript.info/ cross-window-communication 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


0

最初に、実際に何が起こっているのかをいくつか明確にしましょう。分析を支援するため、次のように副作用を導入することなくスクリプトを変更しました。

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 )

上記のスクリプトでドキュメントをロードすると、次の結果が証明されました。 スクリプトの実行出力

出力から何を学びましたか?

  1. ボタンがクリックiframe.contentWindow.document.querySelector( "booking[email]" )される前に、に評価されnullます。したがって、変数fieldは本質的にありましたnull

  2. ボタンをクリックiframe.contentWindow.document.querySelector( "booking[email]" )するnull 前に評価したのはなぜですか?

    • 以来iframeのドキュメントがロードされていなかった、ブラウザ(Safariは)それは親と子フレーム間のセキュリティポリシーを実行するために最適以下と考えます。
  3. 時間によって私はで押さクリックして、ボタンdocument#booking-widget-iframe(子フレーム)が完全にロードされていた、そして親と子フレーム間のセキュリティポリシーの施行を可能にしました。その結果、iframe.contentWindowクロスオリジンフレームポリシーへの準拠に失敗したため、アクセスの試みはすぐにブロックされました。

可能な解決策:

  • 親フレーム内のスクリプトが子フレーム内のオブジェクトへのアクセスを許可されるようにするには、親フレームと子フレームの両方を同じdomain(つまりhttps://bettercleans.launch27.com)からロードする必要がありますport(考慮しているケースには関係ありません))。
  • または、Window.postMessage()に記載されているように、両方のフレーム間の相互作用にポストメッセージングを利用します。

解決策を適用できると仮定すると、ポップアップする別の問題がありますthere。iframe.contentWindow.document.querySelector("booking[email]")まだだろうnull。次の問題の根本的な原因は、booking指定された要素がターゲットドキュメントで見つからなかったためです。つまり、セレクター"booking[email]"に誤りがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.