Iframes получают плохую упаковку для всего, от проблем с безопасностью до проблем с удобством использования и SEO. Несмотря на это, они являются одним из инструментов в нашем распоряжении, и знание того, как их эффективно использовать, может открыть дверь к новым решениям старых проблем. Возможность отправлять данные между iframe и родительской страницей - полезный трюк для предоставления более интегрированных решений, а не традиционный скучный метод iframe «страница-на-странице».

Однако рассмотренный здесь метод предназначен не только для фреймов, он будет работать в любом случае, когда у вас есть доступ к объекту window другой страницы (так что всплывающие окна и встроенные веб-браузеры тоже могут присоединиться к веселью). Однако с iframe легко играть, поэтому мы будем использовать их в этом примере.

Установить двустороннюю связь между дочерней страницей и ее родительской можно несколькими способами. Тем не менее, как правило, рекомендуется использовать `window.postMessage`, если используемые вами технологии поддерживают его (извините, пользователи IE).

Итак, давайте создадим базовую страницу, которая будет нашей родительской.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Parent Page</title>
  </head>
  <body>
    <h2>Container</h2>
    <textarea id="output" cols="30" rows="10" disabled>awaiting data...</textarea>
    <div>
      <input type="text" id="field" value="type something fun here" />
      <button id="send">Send</button>
    </div>
    <div>
      <iframe
        height="500px"
        id="inner"
        src=""
        frameborder="0"
      ></iframe>
    </div>
  </body>
</html>

Здесь у нас очень простая страница. Я буду использовать отключенное текстовое поле для отображения данных из входящих сообщений со встроенной страницы, а также кнопку ввода и кнопку для отправки сообщений на указанную страницу. Кроме того, у нас есть почетный гость, сам iframe, в настоящее время для него нет источника, потому что нам нужно сначала создать страницу для встраивания. Давайте сделаем это.

Встроенная страница

Это страница, которая будет работать внутри iframe или всплывающего окна. Конструктивно мы сделаем что-то очень похожее на родительскую страницу.

<!-- inner.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Embedded Page</title>
  </head>
  <body>
    <h2>Embedded</h2>
    <textarea cols="30" rows="10" disabled id="output">awaiting data...</textarea>
    <input type="text" id="field" />
    <button id="send">Send</button>
  </body>
</html>

Теперь нам нужно загрузить эту страницу в iframe. Самый простой способ сделать это - использовать что-то вроде пакета npm `serve`. Если у вас установлен `npm`, перейдите в каталог, в котором находятся эти файлы, и запустите` npx serve`.

Вы должны получить вывод, показывающий, на каком порту обслуживаются ресурсы. В моем случае они обслуживаются через порт 5000. Когда я посещаю http: // localhost: 5000, мне будет показана родительская страница index.html, а если я перейду на http: // localhost: 5000 / inner.html », я получу страницу, которую хочу встроить.

Это означает, что я могу использовать этот URL-адрес в качестве источника для своего iframe, поэтому сейчас я установлю его как значение моего атрибута `src`.

<iframe
    height="500px"
    id="inner"
    src="http://localhost:5000/inner.html"
    frameborder="1"
></iframe>

После этого, если мы посетим страницу index.html, мы должны теперь увидеть iframe, содержащий нашу другую страницу под ним. Следующим шагом будет написание кода JavaScript для облегчения взаимодействия между двумя страницами.

JavaScript

Во-первых, нам нужно написать код на странице индекса, который будет ждать загрузки iframe и получить ссылку на его объект window, чтобы мы могли вызвать на нем функцию window.postMessage.

Нам также потребуется добавить прослушиватель событий для отправки сообщения, когда мы нажимаем кнопку отправки, и прослушиватель событий для отображения любых сообщений, которые мы получаем со встроенной страницы.

В index.html создайте тег `‹script›` перед концом вашего тега `‹/body›`, который содержит что-то вроде следующего фрагмента.

<script>
      // assign variables with references to the DOM nodes we will be interacting with
      const output = document.getElementById("output");
      const iframe = document.getElementById("inner");
      const button = document.getElementById("send");
      const field = document.getElementById("field");
      // we will assign this value once the iframe is ready
      let iWindow = null;
// This event listener will run when we click the send button
      button.addEventListener("click", () => {
        // don't do anything if the iframe isn't ready yet
        if (iWindow === null) {
          return;
        }
// otherwise, get the value of our text input
        const text = field.value;
// and send it to the embedded page
        iWindow.postMessage(text);
      });
// This event listener will run when the embedded page sends us a message
      window.addEventListener("message", (event) => {
        // extract the data from the message event
        const { data } = event;
// display it in our textarea as formatted JSON
        output.value = JSON.stringify(data, null, 2);
      });
// Once the iframe is done loading, assign its window object to the variable we prepared earlier
      iframe.addEventListener("load", () => {
        iWindow = iframe.contentWindow;
      });
</script>

Однако сам по себе этот JavaScript мало что даст; нам нужно добавить соответствующий код на встроенную страницу, поэтому добавьте еще один тег скрипта в inner.html, содержащий следующее.

<script>
      // set up references to DOM nodes
      const output = document.getElementById("output");
      const button = document.getElementById("send");
      const field = document.getElementById("field");
// create a variable for the parent window. We will assign it once we get the first message.
      let parent = null;
// add an event listener to send messages when the button is clicked
      button.addEventListener("click", () => {
        // don't do anything if there is no parent reference yet
        if (parent === null) {
          return;
        }
// otherwise get the field text, and send it to the parent
        const text = field.value;
        parent.postMessage(text);
      });
// add an event listener to run when a message is received
      window.addEventListener("message", ({ data, source }) => {
        // if we don't have a reference to the parent window yet, set it now
        if (parent === null) {
          parent = source;
        }
// now we can do whatever we want with the message data.
        // in this case, displaying it, and then sending it back
        // wrapped in an object
        output.textContent = JSON.stringify(data);
        const response = {
          success: true,
          request: { data },
        };
        parent.postMessage(response);
      });
</script>

Сохраните все свои файлы, обновите страницу в браузере и попробуйте.

Использование этого метода отправки сообщений открывает совершенно новый уровень интерактивности, когда дело доходит до всплывающих окон, фреймов и встроенных браузеров, открывая путь для некоторых довольно интересных взаимодействий, если вы правильно играете в карты.

Вставьте ссылки на источник:
- index.html - https://pastebin.com/A0HFp6c5
- inner.html - https://pastebin.com/ba6TNXK5