1. ホーム
  2. Web制作
  3. html5

window.postMessage を用いた html5 のクロスドメインデータインタラクション

2022-01-11 14:08:45

背景

H5を組み込んだアプリでは、ページ下にアクティビティ構築プラットフォームを通じて操作学生が作成した教示ページを表示するエリアを設定したいとのことです。このページは、運営学生自身が構築し、入れ替えるもので、製品学生は、この教示ページの内容をH5で全面的に表示させたいと考えています。

業務要件から記述すると、H5(ページA)にiframeで別のH5ページ(ページB)を読み込ませる必要があることです。しかし、技術的な観点からは、いくつか注意すべき点があります。

  • Bページの高さは決まっておらず、Bページはキャンペーン構築プラットフォームで生成され、何がどれだけ表示されるかは不明です。
  • ページAとページBは別ソースなので、iframeのcontentWindowからページBのサイズを直接取得することはできない。

ソリューション

実は、ジョイント1、2のポイントの核心は、AページでBページの高さを取得し、Aページの表示領域の高さを調整して、AページでBページを完全に表示することを実現する必要があることなのです。

当初の考え

ここで、window.postMessageを使って、異なるドメインでのページ通信の問題を解決しようと考えました。ページAは異なるドメインのcontentWindowを通してページBのサイズを積極的に取得できないので、ページBからwindow.postMessageを通してページAに通知し、常に自分が取得できるようにするとよいのではないでしょうか?

しかし、ここで問題なのは、ページBは確定したものではなく、プラットフォーム構築による運用で生成されるものなので、ページBにコード侵入してページAに通知する方法がないことです。

さらなる考察

実際、プラットフォームでコンポーネントを構築することは実現可能です。iframe通信コンポーネント」を開発し、このコンポーネントをベースに「ブリッジ」としてCページを構築すればいいのです。すると、BページもCページも構築プラットフォームで生成され、同じドメインにあるので、CページはiframeのcontentWindowを通じてBページの高さを積極的に取得することができます。最後に、ページAとページCはクロスドメインですが、クロスドメイン通信はwindow.postMessageによって実現でき、ページAはメッセージイベントをリッスンするだけでよいのです。

このようなCページを「橋渡し役」とすれば、運営学生がどのようなページをプラットフォームを通じて公開しても、AページはBページの内容をそのまま表示することができ、Bページは何もする必要がありません。

画像

先行知識

ポストメッセージ

otherWindow.postMessage(message, targetOrigin, [transfer]);


まず、otherWindowは他のウィンドウへの参照ですが、どのような状況で他のウィンドウを取得することができるのでしょうか。iframeのcontentWindow、window.opener(このページが開かれた場所)、window.parent(ページAがiframeを通してページCをネストしたとき、ページCはwindow.parentを通してページAの参照を取得できます)から取得することが出来ます。
メッセージはオブジェクトです。簡単に言えば、転送はデフォルトでディープコピーを行いますので、参照の問題は気にしないでください。具体的なコピールール https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm (ディープコピーを実装する別の方法を見つけた?)

targetOriginは、このパラメータでどのウィンドウがこのメッセージを受信できるかを実装しており、'*'であればすべてのウィンドウになります。URI文字列を渡すと、プロトコル、ホストアドレス、ポートを調べて比較し、3つのうち1つでも一致しなければ通過させないようにします。
詳しくは、こちらをご覧ください。 https://developer.mozilla.org/zh-CN/docs/Web/API/Window

実装

Cページ

まずは「橋渡し役」としてC言語のページを実装してみましょう。このページがメインの実装となります。
/{br まず、ページCはページAからiframeで読み込まれているので、ここではURL上のパラメータを取得することでページBへのリンクを取得します。

const src = getQueryString('src');

リンクを取得したページCは、iframeによってページBを読み込み、ドキュメントに追加しています。ページBへのリンクを取得できるようにするためには、Bページのonloadイベントが発生した後、ページ上の画像が読み込まれた時点でリンクを取得する必要があります。

const iframe = document.createElement('iframe');
iframe.addEventListener('load', () => {
    // Key steps
});
iframe.src = src;
iframe.style.visibility = 'hidden';
document.body.appendChild(iframe);

最後に、onload イベントの主要なステップを実装します。ページ B の高さを取得し、高さパラメータを postMessage を介してページ A に送信します。
/{br ページBの高さを取得する。

const doc = iframe.contentDocument;
const iframeHeight = Math.max(doc.body.clientHeight, doc.documentElement.clientHeight, doc.body.scrollHeight, doc.documentElement. scrollHeight);

window.parentでページAのwindowオブジェクトへの参照を取得し、最後にwindow.parent.postMessageでページAにメッセージを送信します。

if (window.parent) {
  window.parent.postMessage(
    {
      type: 'resize-iframe',
      data: {
        height: iframeHeight
      }
    },
    '*'
  );
}

Aページ

メッセージイベントを通じて最終的な高さを取得し、Bページのiframeの高さを調整します。

const resizeHandler = (e) => {
  const data = e.data;
  if (data.type === 'resize-iframe') {
    const { height } = data.data;
    // The minimum height of 400 is set here
    this.height = Math.max(400, height);
  }
};
window.addEventListener('message', resizeHandler);

概要

window.postMessageの方法でクロスドメインは、実際に練習するのも初めて、常にいくつかのインタビューのレビュー資料で理解する前に、毎日のクロスドメインは、基本的にCORSシナリオ(実際には、CORSも何もするフロントエンドではありません)、さらにJSONPとされていません。
ビジネスでは、問題を解決するために一般的ではない方法を使用することができます、それは良い感じ、少なくとも知識は言葉の中に残らないでしょう〜。

今回はhtml5でwindow.postMessageを使ったクロスドメインデータ対話について紹介します、より関連するhtml5 window.postMessageクロスドメインコンテンツはスクリプトハウスの過去記事を検索するか以下の関連記事を引き続きご覧ください、今後ともスクリプトハウスをよろしくお願いします!