CSS:您可以在 `:host()` 选择器中使用 `:has` 吗?

问题描述 投票:0回答:1

在下面的示例中,我尝试根据

**host**
是否具有具有
empty
属性的开槽元素来设置其样式。如果它确实有这样的元素,那么我希望添加一个柠檬绿边框:

class Component extends HTMLElement {
    constructor() {
    super().attachShadow({mode:'open'});
    const template = document.getElementById("TEMPLATE");    this.shadowRoot.appendChild(template.content.cloneNode(true));
  }
}
window.customElements.define('wc-foo', Component);
<template id="TEMPLATE">
  <style>
      :host(:has(::slotted([empty]))) {
         border: 2px solid lime;
      }
  </style>
  <div>Custom web component should have a lime border
  </div>
  <slot></slot>
</template>

<wc-foo>
  <div empty>"Empty Div"</div>
</wc-foo>

但是这不起作用,我不知道为什么。猜测可能是因为

:host()
选择器必须是一个简单的选择器。还有其他方法可以实现吗?

PS:这个问题不是如何使用“:host”(或“:host()”)和“:has()”的重复,因为这是关于选择主机的孩子,而我正在尝试选择主机依赖于它的子节点。

css web-component native-web-component
1个回答
0
投票

在撰写此答案时,

:host(:has(...))
选择 light DOM 仅在 Safari 中实现。

因此以下示例目前仅适用于 Safari:

class WcFoo extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode: 'open'});
    this.shadowRoot.innerHTML = `
    <style>
      :host {
        display: block;
        margin: 1em;
      }
      :host(:has([empty])) {
        border: 4px solid lime;
      }
    </style>
     <div>Custom web component should have a lime border</div>
    <slot></slot>
`;
  } 
}

customElements.define('wc-foo', WcFoo);
<h3>Preview this example using Safari</h3>

<wc-foo>
  <div empty>"Empty Div"</div>
</wc-foo>

<wc-foo>
  <div>"No empty attribute"</div>
</wc-foo>

在研究这个问题时,我发现了一些可能提供更多背景信息的 GitHub 问题:https://github.com/web-platform-tests/interop/issues/208。 这个仅限 Safari 的答案也来自 Westbrook 的 GitHub 评论:https://github.com/w3c/webcomponents-cg/issues/5#issuecomment-1220786480

当今适用于所有浏览器的解决方案是什么?

您可以将属性反映到主机上以设置主机的样式。要检测您的元素已被包含

empty
属性的元素插入槽,您可以使用
slotchange
事件。 在 slotchange 事件中将样式属性反映到主机上,并使用选择器:
:host([empty])
添加石灰边框。

class WcFoo extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({
      mode: 'open'
    });
    this.shadowRoot.innerHTML = `
        <style>
          :host {
            display: block;
            margin: 1em;
          }
          :host([empty]) {
            border: 4px solid lime;
          }
        </style>
         <div>Custom web component</div>
        <slot></slot>
    `;
    this.shadowRoot.querySelector('slot').addEventListener('slotchange',
      (evt) => {
        const hasEmpty = evt.target.assignedElements()
          .some(el => el.matches('[empty]'));
        if (hasEmpty) {
          this.setAttribute('empty', '');
        } else {
          this.removeAttribute('empty');
        }
      }
    );
  }
}

customElements.define('wc-foo', WcFoo);
<wc-foo>
  <div empty>"Has lime border"</div>
</wc-foo>

<wc-foo>
  <div>"Will not have border"</div>
</wc-foo>

© www.soinside.com 2019 - 2024. All rights reserved.