UNPKG

joicomponents

Version:

Design patterns to build native web components

114 lines (104 loc) 3.72 kB
<template id="portrait"> <style> green-frame { display: block; width: 300px; height: 300px; } #frameTwo { height: 1.2em; } </style> <green-frame id="frameOne"> <slot>a picture</slot> </green-frame> <green-frame id="frameTwo"> <slot name="label">of somebody</slot> </green-frame> </template> <template id="frame"> <style> :host { border: 4px solid green; } </style> <slot></slot> </template> <script> class PortraitFrame extends HTMLElement { constructor() { super(); this.attachShadow({mode: "open"}); const template = document.querySelector("#portrait").content.cloneNode(true); this.shadowRoot.appendChild(template); this.shadowRoot.addEventListener("slotchange", this.slotchangeCallback.bind(this)); } slotchangeCallback(event) { console.log(this.id, event.composedPath()); } } class GreenFrame extends HTMLElement { constructor() { super(); this.attachShadow({mode: "open"}); const template = document.querySelector("#frame").content.cloneNode(true); this.shadowRoot.appendChild(template); this.shadowRoot.addEventListener("slotchange", this.slotchangeCallback.bind(this)); } slotchangeCallback(event) { console.log(this.id, event.composedPath()); } } customElements.define("green-frame", GreenFrame); customElements.define("portrait-frame", PortraitFrame); </script> <portrait-frame id="portrait"> <h2>¯\_(ツ)_/¯</h2> <span slot="label">self-portrait, by ivar</span> </portrait-frame> <h3>SlotchangeNipSlip #3: CreateRedundantSlotchangeEvents </h3> We start viewing the situation from HTML. <ol> <li> A h2 and span element are declared in the top most lightDOM. </li> <li> The slot elements in the portrait-frame shadowDOM are chained to the respective slot elements in the green-frame elements' shadowDOMs. </li> <li> Then, h2 and span along with their two slot elements in the portrait-frame shadowDOM are transposed into two different green-frame elements and their inner slots. </li> <li> From the perspective of HTML, this should trigger a total of two slotchange events, that each trigger two event listeners, logging a total of four events. </li> </ol> But, in JS, six(?!) slotchange events are triggered. <ol> <li> frameOne (2) [slot, document-fragment]<br> This event is triggered as the first slot in portrait-frame is transposed to the inner slot in the first green-frame element. </li> <li> frameTwo (2) [slot, document-fragment]<br> This event is triggered as the first slot in portrait-frame is transposed to the inner slot in the first green-frame element. </li> <li> frameOne (5) [slot, slot, document-fragment, green-frame#frameOne, document-fragment]<br> portrait (5) [slot, slot, document-fragment, green-frame#frameOne, document-fragment]<br> "¯\_(ツ)_/¯" is added to the portrait-frame element. This element is then transposed to the portrait-frame element and then the green-frame#one. The green-frame#one slotchange event listener is triggered first, then the portrait. </li> <li> frameTwo (5) [slot, slot, document-fragment, green-frame#frameTwo, document-fragment]<br> portrait (5) [slot, slot, document-fragment, green-frame#frameTwo, document-fragment]<br> "self-portrait, by ivar" is added to the portrait-frame element. This element is then transposed to the portrait-frame element and then the green-frame#two. The inner, green-frame#two slotchange event listener is triggered first, then the outer portrait-frame event listener. </li> </ol>