background

In THE H5 embedded in an App, the product hopes to set up an area below the page to display the teaching page generated by the operation students through the activity building platform, which is built and replaced by the operation students themselves. The product students hope that the CONTENT of this teaching page can be completely displayed in H5.

In terms of service requirements, one H5 page (A page) needs to load another H5 page (B page) through iframe. But from a technical point of view there are a few caveats:

  1. The height of the B page is uncertain. The B page is generated by the platform of the event, and it is not known what and how much content will be displayed.
  2. Page A and page B are from different sources, so they cannot pass iframe directlycontentWindowGet the size of page B.

The solution

In fact, the core of point 1 and 2 is to obtain the height of page B on page A, and then adjust the height of the display area of page A to achieve the function of displaying page B completely on page A.

A preliminary idea

Here I came up with the idea of using window.postMessage to solve the problem of page communication between different domains. Page A can’t get the size of page B through different fields’ contentWindow, so let page B notify page A through window.postMessage.

But the problem comes, page B is not determined, it is generated by the operation through building the platform, that is to say, there is no way to inform page A of page B through code intrusion.

Further thoughts

In fact, the components in the scaffolding platform are achievable. You can develop an “iframe communication component” and build a C page based on this component as a “bridge.” Therefore, since both page B and page C are generated by the building platform and are in the same domain, page C can actively obtain the height of page B through the contentWindow of iframe. Finally, although page A and page C are cross-domain, they can realize cross-domain communication through window.postMessage. Page A only needs to listen for message events.

With such A page C as A “bridge”, no matter what the operation students publish through the platform in the future, page A can fully display the content of page B, and page B does not need to do anything.

Front knowledge

postMessage

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

First of all, otherWindow is a reference to another window, so when can I get another window? You can use iframe’s contentWindow, window.opener (where the page is opened from), and window.parent (when A nested C page with iframe, C page gets A reference from WINDOw.parent).

Message is an object that, in short, is deep-copied by default when transmitted, so don’t worry about references. Copy rules: developer.mozilla.org/en-US/docs/… (Another way to implement deep copy?)

TargetOrigin uses this parameter to specify which Windows will receive the message, and if it is ‘*’, it will be all. You can pass in a URI string, which will be compared by protocol, host address, or port. If one of the three does not match, it will not pass through.

More details can be found at developer.mozilla.org/zh-CN/docs/…

implementation

C page

Let’s start with the C page as the bridge, which is the main implementation.

First of all, page C is loaded by page A via iframe. Therefore, the link of page B is obtained by obtaining parameters in the URL.

const src = getQueryString('src');
Copy the code

After obtaining the link, page C loads page B with iframe and adds it to the document. In order to get the link to page B, we need to get it after the onload event of page B is triggered, and the picture on the page has been loaded.

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

Finally, the key steps in the onLoad event are realized: obtain the height of page B and send height parameters to page A through postMessage.

Get the height of page B:

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

Through the window. The parent window object reference, access to A page finally through the window. The parent. PostMessage sending messages to A page:

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

A page

What page A does is simpler: one iframe loads page B and another iframe loads page C. Get the final height via message event, adjust the height of iframe on page B.

const resizeHandler = (e) = > {
  const data = e.data;
  if (data.type === 'resize-iframe') {
    const { height } = data.data;
    // Set the minimum height to 400
    this.height = Math.max(400, height); }};window.addEventListener('message', resizeHandler);
Copy the code

conclusion

In fact, it is the first time to practice cross-domain through windower. postMessage. I have always learned from some interview review materials before, but the daily cross-domain is basically a CORS scenario (in fact, CORS does not use the front end to do anything), and even JSONP is not used.

Business can use not commonly used way to solve problems, feel good, at least knowledge will not stay in the literal ~