【问题标题】:HTML web component does not use shadow DOM styleHTML web 组件不使用 shadow DOM 样式
【发布时间】:2020-12-05 02:59:31
【问题描述】:
我创建了一个普通的 Web 组件或 HTML 元素。它只显示两个链接。
为了封装这个东西,我使用了 shadow DOM。但是,它似乎没有被封装。在 DOM 树中,它位于 #shadow-root 内部,这很好。
为什么 Web 组件使用全局样式而不是我在模板中为我的 Web 组件提供的样式?
文本是红色的,我希望它是绿色的。
class MyEl extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: "open" });
}
connectedCallback() {
const template = `
<style>
a {
color: green;
}
</style>
<slot></slot>`;
this.shadow.innerHTML = template;
}
}
window.customElements.define("my-el", MyEl);
a {
color: red
}
<my-el>
<a href="example.com">Item1</a>
<a href="example.com">Item2</a>
</my-el>
【问题讨论】:
标签:
javascript
html
web-component
custom-element
【解决方案1】:
完整、详细的解释在:::slotted CSS selector for nested children in shadowDOM slot
TL;DR
您的链接位于 lightDOM 中,因此由其 DOM 设置样式(在您的代码中为文档 DOM)
将节点从 lightDOM 移动到 shadowDOM 是一种“解决方案”;但那时你没有使用插槽。
仅供参考,您的代码可以压缩为:
class MyEl extends HTMLElement {
constructor() {
super().attachShadow({ mode: "open" })
.innerHTML = `<style>a{color:green}</style><slot></slot>`;
}
}
window.customElements.define("my-el", MyEl);
更多 SLOT 相关答案可以通过 StackOverflow 搜索找到:Custom Elements SLOTs
【解决方案2】:
虽然这个问题已经有一个公认的答案,但对于大多数用例来说,将插槽的子级移动到 shadowRoot 是不可取的。
您可能想要做的是使用::slotted() 选择器。
请记住,通过 ::slotted() 选择器应用于插槽子项的样式仅充当“默认”样式,并且仍然可以通过在轻量级 DOM 中使用样式来覆盖。
例如,检查你的 sn-p 的这个编辑版本:
如您所见,这次my-el 尝试同时应用颜色和文本装饰样式来锚定 (<a>) 任何插槽中的子级。
但是,在 light dom 中,我们有一个覆盖颜色的 a.special 选择器,因此 <a class="special"> 将是红色,而不是绿色
class MyEl extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: "open" });
}
connectedCallback() {
const template = `
<style>
::slotted(a) {
color: green;
text-decoration: none;
}
</style>
<slot></slot>`;
this.shadow.innerHTML = template;
}
}
window.customElements.define("my-el", MyEl);
a.special {
color: red
}
<my-el>
<a href="example.com">Item1</a>
<a class="special" href="example.com">Item2</a>
</my-el>
【解决方案3】:
请注意这一行,您必须将元素移动/复制到阴影中,例如:
this.shadow.innerHTML = this.innerHTML + template;
我已经添加了这个来证明只有内联样式将应用于阴影 dom 元素..所以 SD 中复制的链接正在使用您的样式:)
所以 red 将是 GLOBAL,green 将是 SHADOW 元素
class MyEl extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.shadow = this.attachShadow({ mode: "open" });
const template = `
<style>
a {
color: green;
}
</style>
<slot></slot>`;
this.shadow.innerHTML = this.innerHTML + template;
}
}
window.customElements.define("my-el", MyEl);
a {
color: red
}
<my-el>
<a href="example.com">Item1</a>
<a href="example.com">Item2</a>
</my-el>