考虑以下代码:
//js
class FooBar extends HTMLElement {
constructor(){
super();
}
}
customElements.define('foo-bar', FooBar);
<!-- html -->
<foo-bar>
<h1>Test</h1>
</foo-bar>
这将在浏览器中显示»Test«。
如果构造函数更改为:
constructor () {
super();
this.shadow = this.attachShadow({ mode: 'open' })
}
»Test«消失了,因为现在有一个影子根了。
如果构造函数进一步更改为
constructor () {
super();
this.shadow = this.attachShadow({ mode: 'open' });
this.shadow.appendChild(document.createElement('slot'));
}
再次出现»Test«,因为现在
<foo-bar>
的所有子节点都有一个默认插槽但是,如果影子根目录中没有
<slot />
,子节点会发生什么情况。它们仍然出现在this.children
中,并且其style.display
属性仍然是""
。所以它们在dom之内,却未被渲染,即使您讲相反的话?这里到底发生了什么? 最佳答案
完整的详细解释在:::slotted CSS selector for nested children in shadowDOM slot
<foo-bar>
<h1>Test</h1>
</foo-bar>
H1是 lightDOM ,“添加” 到 shadowDOM/root 内容是反射(reflect)了到 shadowDOM ,没有移动!
H1始终保留在lightDOM中:
appendChild
(或任何DOM移动操作)显式移动它您说:所以它们在dom之内,但没有呈现,即使CSS告诉您相反的情况?
不,它们是呈现的,就像任何普通的DOM元素一样。只是不再可见。
您可以通过在lightDOM中包含一个SCRIPT标记来进行测试。它会渲染并执行!
在下面的代码段中
您使用
this.querySelector("span").innerHTML="weird";
引用 lightDOM 但是用
this.shadowRoot.querySelector("span").innerHTML="weird";
引用 shadowDOM 不起作用不起作用,因为DIV(带有SPAN)位于中的黑盒中
<template id="MY-ELEMENT">
<style>
:host {
display: inline-block;
font-family: Arial;
}
::slotted(div){
color:blue;
}
::slotted(span){
color:gold; /* alas, you can style the 'box', not elements inside */
}
</style>
<h3><slot></slot></h3>
</template>
<style>
span {
background:lightcoral; /* from global/host CSS, style slotted content lightDOM */
}
</style>
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super().attachShadow({mode: 'open'})
.append(document.getElementById(this.nodeName).content.cloneNode(true));
}
});
</script>
<my-element>
<div>Hello <span>Component</span> World!</div>
</my-element>
检查F12开发工具中的组件:
Chrome和Firefox:
DIV不在shadowDOM/根目录中,在lightDOM中保持不可见
所有元素/样式都将始终反射(reflect)到shadowDOM/root
点击“显示”将您带到lightDOM
注意:在F12控制台中编辑DIV,您将立即看到更改将反射(reflect)到shadowDOM
SLOTs和lightDOM是实时连接
通过更改
<slot name=...>
,您可以进行交互(想想路线,选项卡,答案),而以前需要更多的编码(还记得那些jQuery显示/隐藏天数吗?)<template id="MY-ELEMENT">
Custom Element SLOTs are:
<slot name=answer></slot>
</template>
<style>
img { /* style all IMGs in lightDOM */
max-width: 100vw;
max-height: 70vh;
}
</style>
<script>
customElements.define('my-element', class extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'})
.append(document.getElementById(this.nodeName).content.cloneNode(true));
this.onclick = (evt) => {
const answer = evt.composedPath()[0].innerText; // button label
this.shadowRoot.querySelector('slot').name = answer;
this.children[0].slot = answer;//include lightDOM buttons again
}
}
});
</script>
<my-element>
<span slot=answer><button>Cool</button><button><b>Awesome</b></button><button>Great</button></span>
<div slot=Cool><img src="https://i.imgur.com/VUOujQT.jpg"></div>
<span slot=Awesome> <h3>SUPER!</h3></span>
<div slot=Awesome><img src="https://i.imgur.com/y95Jq5x.jpg"></div>
<div slot=Great><img src="https://i.imgur.com/gUFZNQH.jpg"></div>
</my-element>
可通过StackOverflow搜索找到更多与SLOT相关的答案:Custom Elements SLOTs