使用 CSS 选择器,例如 :first-child inside shadow dom

Use CSS selectors like :first-child inside shadow dom

有什么方法可以在阴影 dom 内使用 css 选择器,如 :first-child、:not(:last-child)?

例子是这样的

CustomElement.html

<div id="parent-div>
 <slot></slot>
</div>

App.html

<div>
 <custom-element>
   <div class="heading">Main Heading</div>
   <div class="item">item 1</div>
   <div class="item">item 1</div>
   <div class="item">item 1</div>
   <div class="heading">Second Heading</div>
   <div class="item">item 1</div>
   <div class="item">item 1</div>
   <div class="item">item 1</div>
 </custom-element>
</div>

我想做的是找出第一个 .heading 元素并向其添加自定义样式。由于 <div class=heading"> 实际上是一个组件,因此我无法为其添加自定义样式,仅将其视为第一个标题。

P.S.:- 我正在使用 angular-elements,如果有帮助的话

和我一样的回答gave in your question yesterday

Slotted content is not moved to shadowDOM,

it remains (invisible) in lightDOM

and is REFLECTED in the shadowDOM <SLOT>

因此 SLOTTED 内容样式是在 <custom-element> 所在的 CSS 范围内完成的。

::slotted( x )

来自docs

::slotted can only take a compound selector (in the parenthesis). The reason of this > restriction is to make a selector style-engine friendly, in terms of performance.

所以你可以用你的结构做:

 ::slotted(.heading) { }
or
 ::slotted(:first-child) { }

但不是:

 ::slotted(.heading:first-child)

因为是复合选择器,不是(简单)复合选择器

因此您的标题可以在全局 CSS 中设置样式,并将 REFLECT 插入内容:

my-element div.heading{
  background:blue;
  color:white;
}

如果要封装此样式,则必须将所有内容包装在(另一个)组件中

您可以定位 所有 未命名的插槽内容:

    ::slotted(:not([slot])){
      font-weight:bold;
    }

这是另一个使用开槽样式的 JSFiddle:

https://jsfiddle.net/CustomElementsExamples/whtjen3k/

我在 JS 方式.

中找到了解决方法

对于每个插槽,我们都有一个名为 (slotchange) 的事件处理程序。通过使用它,我们可以在插槽更改时获取插槽的 DOM 事件。像这样(HTML)

<custom-element (slotchange)="onSlotChanged($event)"></custom-element>

JS

onSlotChanged($event) {
 console.log($event) // Go and research yourself about this event, you'll find many things usefull.
 $event.target.assignedNodes() // This will give you the array of every elements, that are in side of the shadow dom
 // Example usage, adding the margin-bottom to only first time (css :firsh-child)
 $event.target.assignedNodes()[0].shadowRoot.getElementById('some-id').style.marginBottom = '10px'
}

如果只需要给元素加一个属性,就不用像"node.shadowRoot"那样去查询shadowDom了。但是,如果你想访问那个元素的 shadowRoot 里面的元素,你必须使用那个