slot
is good to make a reusable web component, however, it has a limit so far. What I faced is the style problem. You just can't define the style inside a component, even you know what the inject content's structure would be.
Details found from my post in github here
I write a component, and try to inject content through slot
from the outside and try to add style to the specific content in the component's shadow root.
Demo
HTML file
<my-navbar>
<ul>
<li>link1</li>
<li>link2</li>
<li>link3</li>
</ul>
</my-navbar>
JS file
customElements.define('my-navbar', class extends HTMLElement {
constructor () {
super();
const sr = this.attachShadow({ mode: 'open' });
sr.innerHTML = `
<style>
/*worked*/
::slotted(ul)
{
color:green;
}
/*
Suppose I know the outside content is "ul li", and I directly define the
style after they injected into component's slot. However, it just doesn't
work because the slotted selector is just a compound selector. It can only
affect the first layer 'ul'. It can't affect the child dom 'li' */
::slotted(ul li)
{
color:red;
}
</style>
<slot></slot>
`;
}
});
However, it just doesn't work directly because you just can't use a complex selector for ::slot(simple_selector)
Reason
I found an indirect solution, and that's to re-append the outside content into the slots inside the component's shadow root.
Demo
HTML file
<my-navbar>
<!--a dom defined a slot property-->
<ul slot='t'>
<li>link1</li>
<li>link2</li>
<li>link3</li>
</ul>
<!--A dom not define slot property-->
<span>1234</span>
</my-navbar>
JS file
customElements.define('my-navbar', class extends HTMLElement {
constructor () {
super();
const sr = this.attachShadow({ mode: 'open' });
sr.innerHTML = `
<style>
ul li
{
color:red;
}
</style>
<slot name='t'></slot>
<slot ></slot>
`;
// Do something later...
setTimeout(this.appendOutsideSlotContentIntoInsideSlot.bind(this), 1000)
}
appendOutsideSlotContentIntoInsideSlot()
{
// Insert outside dom element which has define slot property into the specify slot inside the shadow root
debugger;
for (let objIndex=0;objIndex<this.children.length;)
{
var obj=this.children[objIndex];
if(obj.slot){
var slot=this.shadowRoot.querySelector('slot[name='+obj.slot+']');
if(slot)
{
slot.appendChild(obj);
continue;
}
}
objIndex++;
}
// Insert the rest dom which has not define slot property values into the anonymous slot
var defaultSlot=Array.prototype.slice.call(this.shadowRoot.querySelectorAll('slot')).filter(function(el){ return !el.name})[0];
debugger;
if(defaultSlot)
{
while (this.children.length>0)
{
defaultSlot.appendChild(this.children[0])
}
}
}
});
Well, it works for the contents which have defined the slot property, but doesn't work again with content that has no slot property.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…