我定义了自己的自定义元素,并发现在阴影dom中添加其子元素非常方便,这主要是因为我可以在自定义元素构造函数中添加它,而完全相同的构造函数不允许我添加“常规”元素孩子们。
自定义元素的构造函数不允许您添加子对象,因为新元素在创建后就应该为空。
我想知道是否有一种简单的方法来使CSS和文档中的样式能够影响阴影dom中的元素。我希望轻型dom的选择器能够到达阴影dom中的这些元素。
我的自定义元素之一是“项目”。我将创建很多它们来填充列表。我不喜欢在每个项目实例的阴影dom中重复相同的样式标签的想法,因此我正在寻找一个放置所有我的项目的样式标签的地方。
我读了许多有关影子域以及内部样式如何不影响边界元素的文章,但是其中任何一个都回答了我的问题。
有什么想法吗?谢谢!
答案 0 :(得分:2)
当前版本的shadowDOM要求您将CSS放在shadowDOM内。
大多数CSS都非常小,每个元素仅增加几个字节到几百个字节。我看到的一些最大的CSS副本每个副本中都添加了约2k的CSS。但这与DOM结构中表示的数据相比仍然很小。
有一些东西会从外面流失,例如字体信息,但是没有很多。
以下是一些可以从外部影响到的方法:
CSS Variable允许您将变量设置为CSS内使用的值,无论是否在shadowDOM中。
可以捕获属性并将其迁移到shadowDOM CSS中。我有一些使用属性定义主题的组件。
还可以获取属性并将其应用于内部CSS。
讨论中还有其他方法,但是这些方法必须等到V2。
class MyEL extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'}).innerHTML = `
<style>
.outer {
color: var(--myColor, 'black');
</style>
<div class="outer">
<h4>Title</h4>
<slot></slot>
</div>`;
}
static get observedAttributes() {
return ['bgcolor'];
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal !== newVal) {
this.shadowRoot.querySelector('.outer').style.backgroundColor = newVal;
}
}
get border() {
return this.shadowRoot.querySelector('.outer').style.border;
}
set border(value) {
this.shadowRoot.querySelector('.outer').style.border = value;
}
}
customElements.define('my-el', MyEL);
setTimeout(() => {
document.querySelector('my-el').border = '2px dashed blue';
},1000);
const btn = document.getElementById('toggle');
let color = '';
btn.addEventListener('click', () => {
color = color === '' ? 'white' : '';
document.querySelector('my-el').style.setProperty('--myColor', color);
});
<my-el bgcolor="red"></my-el>
<hr/>
<button id="toggle">toggle</button>
答案 1 :(得分:0)
首先,我不知道您所说的自定义组件应该为空的意思是什么……我认为那不是真的,因为我找不到任何说明该要求的文档。此外,以下对我来说很好用:
customElements.define("my-element", class extends HTMLElement {
constructor() {
super();
// Add a `span` element to the component's light-DOM.
const span = document.createElement("span");
span.innerHTML = "Hello, World!";
this.appendChild(span);
// Add a `slot` element to the component's shadow-DOM (so that the light-DOM gets rendered).
this.attachShadow({ mode: "open" }).innerHTML = "<slot></slot>";
}
});
<my-element></my-element>
如果您的意思是如果无法将light-DOM内容分配给shadow-DOM中的slot
元素,那么您是正确的。
无论如何,那只是一个副节点。回到关于从Web组件外部设置阴影DOM样式的问题...
除了@Intervalia's quite thorough answer,您还可以查看一下Web组件的::part
和::theme
伪元素。
类似这样的东西:
customElements.define("my-element", class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" }).innerHTML = `
<style>
* {
position: relative;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:host {
display: inline-block;
height: 150px;
width: 200px;
}
#outer {
height: 100%;
padding: 20px;
background: lightblue;
border: 5px solid blue;
}
#inner {
height: 100%;
background: lightgreen;
border: 5px solid green;
}
</style>
<div id="outer" part="foo">
<div id="inner" part="bar">
</div>
</div>
`;
}
});
#second {
width: 300px;
}
#second::part(bar) {
background: lightcoral;
border: 10px dotted red;
}
<my-element id="first"></my-element>
<my-element id="second"></my-element>
有关详细说明,我想参考:
请注意,::part
伪元素和相应的part
属性当前仅在Chrome和Opera中起作用。 FireFox将在版本69中支持它,但是首先您必须在其layout.css.shadow-parts.enabled
页面中将true
设置为about:config
(这使我怀疑它对于使用Firefox的普通用户是否非常有用,所以我希望Mozilla会默认将其默认打开)。