joicomponents
Version:
Design patterns to build native web components
76 lines (66 loc) • 2.62 kB
HTML
<h1>Hello world!</h1>
<hr>
<iframe-updater srcdoc="<h1>Hello sunshine!</h1>"></iframe-updater>
<script type="module">
(function () {
const iframeScript = `
<script>
(function(){
window.addEventListener("message", function(e){
console.log("inside iframe: ", JSON.parse(e.data));
});
parent.postMessage("ready", "*");
setTimeout(function(){parent.postMessage("one", "*")}, 1000);
setTimeout(function(){parent.postMessage("two", "*")}, 2000);
setTimeout(function(){parent.postMessage("three", "*")}, 3000);
})();
</scrip` + "t>";
class IframeUpdater extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
this.shadowRoot.appendChild(document.createElement("iframe"));
this._iframe = this.shadowRoot.children[0];
this._iframe.setAttribute("sandbox", "allow-scripts");
this._ready = false;
window.addEventListener("message", this.onMessage.bind(this))
}
static get observedAttributes() {
return ["srcdoc"];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === "srcdoc") {
const src =
iframeScript +
(newValue || "");
const blob = new Blob([src], {type: "text/html"});
this._iframe.setAttribute("src", URL.createObjectURL(blob));
}
}
sendMessage(value) {
if (!this._ready) { //delay sending this message until
console.log("delaying 1 rAF...");
return requestAnimationFrame(this.sendMessage.bind(this, value)); //inner iframe is ready to receive messages
}
this._iframe.contentWindow.postMessage(value, "*");
}
onMessage(e) {
if (e.source !== this._iframe.contentWindow)
return;
if (e.data === "ready")
return this._ready = true;
console.log("message received in parent: ", e.data);
}
}
customElements.define("iframe-updater", IframeUpdater);
const iframeUpdater = document.querySelector("iframe-updater");
iframeUpdater.sendMessage(JSON.stringify(0));
setTimeout(() => iframeUpdater.sendMessage(JSON.stringify(1)), 1000);
setTimeout(() => iframeUpdater.sendMessage(JSON.stringify(2)), 2000);
setTimeout(() => iframeUpdater.sendMessage(JSON.stringify(3)), 3000);
})();
</script>
<!--
This code is untested. I have only done superficial tests from within devtools in Chrome.
The code should only work in Chrome, Safari, Firefox as template does not work in IE and Edge.
-->