Проблема с выбором элемента в форме бронирования iframe - PullRequest
8 голосов
/ 17 января 2020

Я пытаюсь выбрать поле электронной почты в этой форме бронирования iframe. В конце концов я хочу сделать что-то еще с полем, но сейчас в качестве теста я просто хочу выбрать элемент и изменить местозаполнитель.

Получение этой ошибки, поэтому я выбрал ее неправильно: Uncaught TypeError: Невозможно установить свойство 'placeholder' для null в HTMLButtonElement.changeCopy

Вы можете просмотреть живую версию моего кода здесь и увидеть ошибку в консоли при нажатии кнопки вверху: 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>

Ответы [ 2 ]

6 голосов
/ 21 января 2020

Причина, по которой поле имеет значение 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>

Предупреждение: непроверенный код, но вот основная идея c: со стороны клиента JavaScript, вы можете непосредственно редактировать элементы iframe, поэтому способ связи с ним - отправить сообщение в iframe с помощью iframe.contentWindow.postMessage. На стороне iframe вы можете прочитать это сообщение, которое приходит с «message» прослушивателя событий (или вы можете сделать window.onmessage). Затем вы можете отправить JSON данные или текст в виде сообщения в iframe и прочитать его с помощью e.data. Таким образом, в приведенном выше (непроверенном) примере, когда главной странице github требуется изменить значение заполнителя на определенную сумму c, он просто отправляет объект 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 голосов
/ 27 января 2020

Сначала давайте внесем ясность в то, что действительно происходит. Чтобы помочь в анализе, я изменил ваш сценарий без каких-либо побочных эффектов следующим образом:

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 )

Загрузка документа с помощью вышеуказанного сценария доказала следующий результат: Run output of script

Что мы узнали из вывода?

  1. До нажатия кнопки iframe.contentWindow.document.querySelector( "booking[email]" ) оценивается как null. Поэтому переменная field была по существу null.

  2. Почему iframe.contentWindow.document.querySelector( "booking[email]" ) оценивается как null до нажатия кнопки ?

    • Поскольку документ iframe не был загружен, браузер (Safari) счел неоптимальным запуск политик безопасности между родительским и дочерним фреймами.
  3. By Когда я нажал кнопку Click , document из #booking-widget-iframe (дочерний фрейм) был загружен полностью, и было применено применение политик безопасности между родительским и дочерним фреймами. Следовательно, попытка доступа к iframe.contentWindow была незамедлительно заблокирована из-за неудовлетворительного соответствия политике фреймов.

Возможные разрешения:

  • Чтобы скриптам в родительском фрейме был разрешен доступ к объектам в дочернем фрейме, оба родительских и дочерних фрейма должны быть загружены из одних и тех же domain (то есть https://bettercleans.launch27.com) и port (не имеет значения для рассматриваемого случая).
  • В качестве альтернативы используйте пост-сообщения для взаимодействия между обоими кадрами, как описано в Window.postMessage () .

Если предположить, что вы можете применить разрешение, возникнет еще одна проблема ?. iframe.contentWindow.document.querySelector("booking[email]") будет еще null. Причина root последующей проблемы будет связана с тем, что в целевом документе не найден элемент с именем booking. Другими словами, селектор "booking[email]" ошибочен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...