Zum Inhalt springen

JavaScript-Kommunikation zwischen Fenstern

Die Kommunikation zwischen Fenstern in JavaScript ist für Webentwickler unerlässlich, die den Datenaustausch zwischen verschiedenen Browsing-Kontexten verwalten müssen. Dieser umfassende Leitfaden befasst sich mit den Feinheiten der Kommunikation zwischen Fenstern und bietet detaillierte Erklärungen sowie praktische Beispiele. Unser Ziel ist es, Ihnen das Wissen zu vermitteln, um dieses fortgeschrittene JavaScript-Feature effektiv zu handhaben.

Verständnis der Kommunikation zwischen Fenstern

Die Kommunikation zwischen Fenstern bezeichnet den Prozess des Datenaustauschs zwischen verschiedenen Fenstern oder Frames. Dazu kann die Kommunikation zwischen einem übergeordneten Fenster und einem untergeordneten Fenster (Popup) oder zwischen mehreren Frames innerhalb desselben übergeordneten Fensters gehören.

Szenarien, die Kommunikation zwischen Fenstern erfordern

  1. Popup-Fenster: Wenn ein neues Fenster über window.open() geöffnet wird, wird die Kommunikation zwischen dem übergeordneten und dem untergeordneten Fenster notwendig.
  2. Iframe-Kommunikation: Häufig verwenden Webanwendungen iframes, um Inhalte einzubetten. Eine effektive Kommunikation zwischen dem übergeordneten Fenster und iframes ist entscheidend.
  3. Tabs: Manchmal ist ein Datenaustausch zwischen verschiedenen Tabs erforderlich.

Methoden der Kommunikation zwischen Fenstern

Verwendung von window.postMessage()

Die Methode window.postMessage() bietet eine Möglichkeit, Daten sicher zwischen verschiedenen Fenstern oder Frames zu senden.


html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Cross-Window Communication</title>
  <style>
    #childIframe, #childPopup {
      width: 100%;
      height: 200px;
      border: 1px solid black;
      margin-top: 20px;
    }
  </style>
</head>
<body>
  <h1>Cross-Window Communication Examples</h1>

  <!-- Button to Open Popup -->
  <button id="openPopup">Open Popup</button>
  <div id="parentPopupDisplay"></div>

  <!-- Iframe -->
  <iframe id="childIframe" srcdoc="
    <!DOCTYPE html>
    <html lang='en'>
    <head>
      <meta charset='UTF-8' />
      <title>Child Iframe</title>
    </head>
    <body>
      <div id='childIframeDisplay'></div>
      <script>
        window.addEventListener('message', (event) => {
          // Note: For cross-origin contexts, replace window.location.origin with the hardcoded parent origin.
          if (event.origin !== window.location.origin) return;
          document.getElementById('childIframeDisplay').innerText = 'Message from parent: ' + event.data;
          event.source.postMessage('Hello, Parent Window!', event.origin);
        });
      </script>
    </body>
    </html>
  "></iframe>
  <div id="iframeDisplay"></div>

  <!-- Scripts for Parent Window -->
  <script>
    // Handle Popup Communication
    document.getElementById('openPopup').addEventListener('click', () => {
      const popup = window.open('', 'popupWindow', 'width=600,height=400');
      popup.document.write(`
        <!DOCTYPE html>
        <html lang='en'>
        <head>
          <meta charset='UTF-8' />
          <title>Popup Window</title>
        </head>
        <body>
          <div id='popupDisplay'></div>
          <script>
            window.addEventListener('message', (event) => {
              // Note: For cross-origin contexts, replace window.location.origin with the hardcoded parent origin.
              if (event.origin !== window.location.origin) return;
              document.getElementById('popupDisplay').innerText = 'Message from parent: ' + event.data;
              event.source.postMessage('Hello, Parent Window!', event.origin);
            });
          <\/script>
        </body>
        </html>
      `);
      setTimeout(() => {
        // For cross-origin, replace '*' with the exact target origin (e.g., 'https://example.com')
        popup.postMessage('Hello from parent!', '*');
      }, 1000);
    });

    // Handle Iframe Communication
    const iframe = document.getElementById('childIframe');

    iframe.onload = () => {
      iframe.contentWindow.postMessage('Hello from parent window!', '*');
    };

    window.addEventListener('message', (event) => {
      if (event.origin !== window.location.origin) return;
      if (event.source === iframe.contentWindow) {
        document.getElementById('iframeDisplay').innerText = 'Message from iframe: ' + event.data;
      } else {
        document.getElementById('parentPopupDisplay').innerText = 'Message from popup: ' + event.data;
      }
    });
  </script>
</body>
</html>

In diesem kombinierten Beispiel öffnet das übergeordnete Fenster ein Popup und bettet ein iframe ein. Sowohl das Popup als auch das iframe können über postMessage() mit dem übergeordneten Fenster kommunizieren. Nachrichten werden zur besseren Sichtbarkeit in den jeweiligen div-Elementen angezeigt.

note

While document.write() works for simple demos, modern best practices recommend using DOMParser or Blob URLs to inject content into popups safely.

Zugriff auf Fensterreferenzen

Wenn Sie ein neues Fenster öffnen, erhalten Sie eine Referenz darauf, die zum Manipulieren oder zur Kommunikation mit ihm verwendet werden kann.


html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Direct Manipulation Example</title>
  <style>
    #childIframe {
      width: 100%;
      height: 200px;
      border: 1px solid black;
      margin-top: 20px;
    }
  </style>
</head>
<body>
  <h1>Direct Manipulation Example</h1>

  <!-- Button to Open Popup -->
  <button id="openChild">Open Child Window</button>
  <div id="parentChildDisplay"></div>

  <!-- Iframe -->
  <iframe id="childIframe" srcdoc="
    <!DOCTYPE html>
    <html lang='en'>
    <head>
      <meta charset='UTF-8' />
      <title>Child Iframe</title>
    </head>
    <body>
      <div id='childIframeContent'>Initial Content</div>
    </body>
    </html>
  "></iframe>

  <!-- Scripts for Parent Window -->
  <script>
    document.getElementById('openChild').addEventListener('click', () => {
      const childWindow = window.open('', 'childWindow', 'width=600,height=400');
      childWindow.document.write(`
        <!DOCTYPE html>
        <html lang='en'>
        <head>
          <meta charset='UTF-8' />
          <title>Child Window</title>
        </head>
        <body>
          <div id='childContent'>Initial Content</div>
        </body>
        </html>
      `);
      // Ensure the content is updated after the window has fully loaded
      setTimeout(() => {
        childWindow.document.body.innerHTML += '<p>Message from parent window</p>';
      }, 1000); // Adjust the timeout duration as necessary
    });

    const iframe = document.getElementById('childIframe');

    iframe.onload = () => {
      const iframeDoc = iframe.contentWindow.document;
      iframeDoc.getElementById('childIframeContent').innerText += ' - Updated by Parent Window';
    };
  </script>
</body>
</html>

In diesem Beispiel öffnet das übergeordnete Fenster ein untergeordnetes Fenster und verändert dessen Inhalt direkt, sobald es geladen wurde. Zusätzlich wird der Inhalt eines eingebetteten iframes aktualisiert.

WARNING

Direct DOM manipulation via contentWindow.document or window.opener is restricted by the Same-Origin Policy (SOP) for cross-origin contexts. For secure and reliable communication, always prefer postMessage(). For same-origin popups, window.opener can be used as an alternative to access the parent window directly.

note

When using srcdoc, the iframe content loads asynchronously. The onload handler ensures the DOM is ready, but for complex scenarios, consider triggering communication via a DOMContentLoaded event dispatched from within the iframe.

Verwendung von Local Storage und Session Storage

Local Storage und Session Storage bieten eine alternative Methode für die Kommunikation zwischen Fenstern. Beide Speicheroptionen sind auf die Origin beschränkt, sodass verschiedene Fenster derselben Origin auf gemeinsam genutzte Daten zugreifen können.


html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Local Storage Example</title>
</head>
<body>
  <h1>Local Storage Example</h1>
  <button id="storeData">Store Data</button>
  <button id="retrieveData">Retrieve Data</button>
  <div id="storageDisplay"></div>

  <script>
    // Listen for changes triggered by other windows/tabs
    window.addEventListener('storage', (event) => {
      if (event.key === 'sharedData') {
        document.getElementById('storageDisplay').innerText = 'Updated Data: ' + event.newValue;
      }
    });

    document.getElementById('storeData').addEventListener('click', () => {
      localStorage.setItem('sharedData', 'This is shared data');
    });

    document.getElementById('retrieveData').addEventListener('click', () => {
      const data = localStorage.getItem('sharedData');
      document.getElementById('storageDisplay').innerText = 'Stored Data: ' + data;
    });
  </script>
</body>
</html>

In diesem Beispiel speichert das übergeordnete Fenster Daten in localStorage und ruft sie bei Klick auf die Schaltflächen ab. Um die Synchronisierung zwischen Fenstern zu ermöglichen, wird ein storage-Event-Listener hinzugefügt. Beachten Sie, dass das storage-Ereignis nur in anderen Browsing-Kontexten ausgelöst wird, nicht in demjenigen, der die Änderung ausgelöst hat.

Broadcast Channel API

Die Broadcast Channel API ermöglicht eine einfache Kommunikation zwischen Browsing-Kontexten (Fenstern, Tabs, iframes), die dieselbe Origin teilen.


html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Broadcast Channel Example</title>
</head>
<body>
  <h1>Broadcast Channel Example</h1>
  <button id="sendMessage">Send Message</button>
  <div id="broadcastDisplay"></div>

  <script>
    const channel = new BroadcastChannel('example_channel');

    channel.onmessage = (event) => {
      document.getElementById('broadcastDisplay').innerText = 'Broadcast message received: ' + event.data;
    };

    document.getElementById('sendMessage').addEventListener('click', () => {
      channel.postMessage('Hello from another context!');
    });
  </script>
</body>
</html>

In diesem Beispiel wird ein Broadcast Channel erstellt, und beim Klicken auf die Schaltfläche wird eine Nachricht gesendet. Die Nachricht wird empfangen und in einem div-Element angezeigt.

Um dieses Beispiel korrekt zu testen:

  1. Klicken Sie zweimal auf die Schaltfläche „Try it Yourself“, damit die Beispielseite in zwei verschiedenen Tabs geöffnet wird.
  2. Klicken Sie dann in einem der Tabs/Fenster auf die Schaltfläche „Send Message“.
  3. Sie sollten sehen, dass die Nachricht im anderen Tab/Fenster erscheint.

Die BroadcastChannel-API ist für die Kommunikation zwischen Tabs konzipiert, daher wird die Nachricht von einem Tab/Fenster an alle anderen gesendet, die für dieselbe Origin geöffnet sind (in diesem Fall dieselbe HTML-Datei).

WARNING

When sending data between windows, use JSON to serialize the data, ensuring compatibility and ease of parsing.


javascript
const message = { type: 'greeting', content: 'Hello, Child Window!' };
childWindow.postMessage(JSON.stringify(message), '*');

WARNING

Ensure your cross-window communication logic handles scenarios where the target window is not accessible or closed.


javascript
try {
  childWindow.postMessage('Hello, Child Window!', '*');
} catch (e) {
  console.error('Failed to send message:', e);
}

Fazit

Die Kommunikation zwischen Fenstern in JavaScript ist ein leistungsstarkes Feature, das bei richtiger Anwendung die Interaktivität und das Benutzererlebnis von Webanwendungen erheblich verbessern kann. Durch den Einsatz von Methoden wie window.postMessage(), Local Storage und der Broadcast Channel API können Entwickler den Datenaustausch zwischen verschiedenen Fenstern, Tabs und Frames effizient verwalten. Befolgen Sie bewährte Verfahren, um eine sichere und robuste Kommunikation zu gewährleisten, und nutzen Sie die bereitgestellten Beispiele, um diese Techniken in Ihre Projekte zu integrieren.

Practice

Was ist an der Kommunikation zwischen Fenstern in JavaScript wahr?

Finden Sie das nützlich?

Dual-run-Vorschau — vergleichen Sie mit den Symfony-Routen live.