如何从父项向下设置开槽零件的样式

2022-05-09 00:00:00 css web-component custom-element

如何设置已插入到Web组件中的部件的样式?

我的目标是创建"功能"组件,它只根据它们所处的状态呈现某些部分(使用Redux)。然后在容器中呈现这些组件。 此容器知道它可以预期哪些类型的子项,并应相应地为子项中的部件设置样式。

帖子提要就是一个例子,其中所有帖子都是相同的Web组件,只呈现某些部分。 然后有一个网格提要组件,并在网格中呈现这些帖子。 另一个按时间顺序的提要可能会简单地将帖子一个接一个地呈现出来。 在这两种情况下,帖子本身都不知道它所在的上下文。 我希望容器组件负责布局/样式。

我有点想要与主机上下文相反的内容。 有了主机上下文,POST组件知道它可以位于哪个容器中,并相应地对自己进行样式化。但我想保持我的POST组件纯功能,没有任何样式。(并且不支持主机上下文)

这段代码显示了我尝试在帖子位于my-grid元素中时将其标题变为红色。但我的尝试都没有奏效。

customElements.define('my-grid', class extends HTMLElement {
  constructor() {
    super().attachShadow({
        mode: 'open'
      })
      .append(document.getElementById(this.nodeName).content.cloneNode(true));
  }
});
customElements.define('my-post', class extends HTMLElement {
  constructor() {
    super().attachShadow({
        mode: 'open'
      })
      .append(document.getElementById(this.nodeName).content.cloneNode(true));
  }
});
<template id="MY-GRID">
  <style>
:host {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  grid-auto-rows: minmax(auto, 100px);
}

::slotted(my-post) {
  display: contents;
}

/* Attempts at styling the parts withing the slotted posts */
my-post h1,
 ::slotted(my-post) h1 {
  background-color: red;
}

my-post ::part(test),
 ::slotted(my-post) ::part(test) {
  background-color: red;
}

my-post::part(test),
 ::slotted(my-post)::part(test) {
  background-color: red;
}
  </style>
  <slot></slot>
</template>
<template id="MY-POST">
  <h1 part="title">Title</h1>
</template>
<my-grid>
  <my-post></my-post>
  <my-post></my-post>
  <my-post></my-post>
  <my-post></my-post>
  <my-post></my-post>
</my-grid>


解决方案

您有多个问题

  • 错别字:您将titletest混为一谈::part(x)引用
  • ::slotted is a very simple selector,因此您可以放弃所有这些尝试
  • (根据上面的链接)时隙内容保留在lightDOM中;因此,lightDOM中的元素:
<my-grid>
  <my-post></my-post>
  <my-post></my-post>
  <my-post></my-post>
  <my-post></my-post>
  <my-post></my-post>
</my-grid>

必须从其容器中设置样式...在本例中,主文档DOM

因此需要的所有全局样式为:

  my-post::part(title) {
    background: red;
  }

您可以不在<my-grid>中执行此操作,因为<my-post>不是<my-grid>lightDOM
<my-grid>无法设置其槽内容的样式(仅具有::slotted的‘外层’外观)

我添加了额外的样式、槽和嵌套的<my-post>元素以使事情变得清晰

数据-lang="js"数据-隐藏="假"数据-控制台="真"数据-巴贝尔="假">
<script>
  class GridElements extends HTMLElement {
    constructor() { super().attachShadow({mode: 'open'})
      .append(document.getElementById(this.nodeName).content.cloneNode(true)) }}
  customElements.define('my-grid', class extends GridElements {});
  customElements.define('my-post', class extends GridElements {});
</script>
<template id="MY-GRID">
  <style>
    :host{display:grid;grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)) }
    ::slotted(my-post) { background: green }
  </style>
  <slot></slot>
</template>
<style id="GLOBAL_STYLE!!!">
  body { font: 14px Arial; color: blue }
  my-post::part(title) { background: red }
  my-grid > my-post::part(title) { color: gold }
  my-post > my-post::part(title) { background:lightcoral }
</style>
<template id="MY-POST">
  <h1 part="title"><slot name="title">[Title]</slot></h1>
  <slot>[post body]</slot>
</template>
<my-grid>
  <my-post><span slot="title">One</span></my-post>
  <my-post>Two</my-post>
  <my-post></my-post>
  <my-post>
    <my-post><span slot="title">SUB</span></my-post>
  </my-post>
</my-grid>

::部件样式声明自my-grid

我向my-gridlightDOM:

添加了my-post

https://jsfiddle.net/CustomElementsExamples/j0nxpmuv/

因此,如果您仍然希望声明主DOM中的内容,但样式来自my-grid,则必须将元素从主DOM移动到my-gridlightDOM:

connectedCallback(){
  this.shadowRoot.append(...this.children);
}

更新#1

有关跨越多个阴影DOM边界的信息,请参阅exportParts:

  • https://meowni.ca/posts/part-theme-explainer/
  • https://caniuse.com/mdn-html_global_attributes_exportparts
  • https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/exportparts(2021年1月-尚无文档页面)

相关文章