joicomponents
Version:
Design patterns to build native web components
129 lines (124 loc) • 4.28 kB
HTML
<script>
class PortraitFrame extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = `
<style>
:host(*){
border: 10px solid darkgreen;
width: 300px;
height: 300px;
display: block;
}
green-frame {
box-sizing: border-box;
display: block;
width: 100%;
height: 100%;
}
</style>
<green-frame id="frameOne">
<slot id="outer">a picture</slot>
</green-frame>`;
}
}
class GreenFrame extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = `
<style>
:host {
border: 4px solid green;
}
</style>
<slot id="inner"></slot>`;
this.shadowRoot.addEventListener("slotchange", function (e) {
console.log(e.composedPath(), e.target.assignedNodes(), e.target.assignedNodes({flatten: true}));
});
}
}
customElements.define("green-frame", GreenFrame);
customElements.define("portrait-frame", PortraitFrame);
</script>
<style> pre { margin: 0 } </style>
<script>
document.addEventListener("DOMContentLoaded", function () {
const pf = document.createElement("portrait-frame");//slotchange event
document.querySelector("body").appendChild(pf);
let pre = document.createElement("pre");
pre.innerText = "¯\\_(ツ)_/¯";
pf.appendChild(pre); //slotchange event
pre = document.createElement("pre");
pre.innerText = " | | ";
pf.appendChild(pre); //slotchange event
pre = document.createElement("pre");
pre.innerText = " | 6 | ";
pf.appendChild(pre); //slotchange event
pre = document.createElement("pre");
pre.innerText = " === ";
pf.appendChild(pre); //slotchange event
pre = document.createElement("pre");
pre.innerText = " | | ";
pf.appendChild(pre); //slotchange event
pre = document.createElement("pre");
pre.innerText = " | | | ";
pf.appendChild(pre); //slotchange event
pre = document.createElement("pre");
pre.innerText = " | | | ";
pf.appendChild(pre); //slotchange event
pre = document.createElement("pre");
pre.innerText = " ^ ^ ";
pf.appendChild(pre); //slotchange event
});
</script>
<h3>SlotchangeExplosion #3</h3>
<p>
When we view this situation from HTML, it looks the same as in our previous example SlotchangeExplosion #1.
The only difference is that two empty scripts will be processed along the way.
But, in your console, you should now see 4 (or more) logs. Why is that?
</p>
<p>
The first script deliberately causes the browser to break its creation of the DOM.
This means that the browser will make a "temporary" DOM branch that looks like this:
<pre>
...
< portrait-frame >
#shadowRoot
..
< green-frame >
#shadowRoot
< slot#inner >
< slot#outer >
< pre >¯\_(ツ)_/¯
< pre > | |
---break 1---
</pre>
This is the temporary state of the DOM in which the second slotchange event is dispatched.
And you can see this state in the slot#outer.assignedElements({flatten: true}) which is:
`[pre, pre, pre, script]`
</p>
<p>
The second script does the same with a "temporary" DOM branch that looks like this:
<pre>
...
< portrait-frame >
#shadowRoot
..
< green-frame >
#shadowRoot
< slot#inner >
< slot#outer >
< pre >¯\_(ツ)_/¯
< pre > | |
< pre > | 6 |
---break 2---
</pre>
This is the temporary state of the DOM in which the third slotchange event is dispatched.
And you can see this state in the slot#outer.assignedElements({flatten: true}) which is:
`[pre, pre, pre, script, pre, script]`
</p>
<p>
The last slotchange event occurs when the DOM branch is complete. :
</p>