简体   繁体   English

结合:host()和:has() - 不可能?

[英]Combine :host() with :has() - not possible?

I have a web component with a shadow DOM and a default slot.我有一个带有影子 DOM 和默认插槽的 web 组件。

I need to apply certain styling based on the presence or absence of specific a light DOM descendant.我需要根据是否存在特定的轻型 DOM 后代来应用某些样式。 Please note that I don't need a specific workaround for this specific styling, it's just an example and in the real world the example is alot more complex.请注意,我不需要针对此特定样式的特定解决方法,这只是一个示例,而在现实世界中,该示例要复杂得多。

I also cannot work with regular DOM CSS like xy:has(div) since I need to apply styles to an element in the shadow DOM based on the presence of the div in the light DOM.我也不能像xy:has(div)这样使用常规 DOM CSS,因为我需要根据 light DOM 中 div 的存在将 styles 应用于 shadow DOM 中的元素。

Please note that the code snippet only works in browsers that support constructable stylesheets (eg Safari won't).请注意,代码片段仅适用于支持可构造样式表的浏览器(例如 Safari 不会)。

 const styleStr = `:host { display: block; border: 3px dotted red; }:host(:has(div)) { border-color: green; } `; let css; try { css = new CSSStyleSheet; css.replaceSync(styleStr); } catch(e) { console.error(e) } customElements.define('x-y', class extends HTMLElement { constructor() { super().attachShadow({mode: 'open'}).adoptedStyleSheets.push(css); this.shadowRoot.append(document.createElement('slot')) } })
 <xy>no div - should have red border</xy> <xy> <div>div, should have green border</div> </xy>

I was trying to find if maybe :host() is not accepting :has() , but was unable to find anything on it, neither in the spec, nor on MDN or caniuse.我试图找出:host()是否不接受:has() ,但无法在其上找到任何内容,无论是在规范中,还是在 MDN 或 caniuse 上。

Does anyone have definitive knowledge/reference about this, and can point me to some documentation?有没有人对此有明确的了解/参考,并且可以指出一些文档?

You want to style slotted content based on an element inside the slot您想要根据插槽的元素设置插槽内容的样式

Since <slot> are reflected, (deep dive: ::slotted CSS selector for nested children in shadowDOM slot )由于<slot>被反映出来,(深入研究:::slotted CSS shadowDOM slot 中嵌套子项的选择器
you need to style a <slot> in its container element.您需要在其容器元素中设置<slot>样式。

If you want that logic to be done from inside the Component,如果您希望从组件内部完成该逻辑,
you could do it from the slotchange Event, which checks if a slotted element contains that DIV您可以从slotchange事件中执行此操作,该事件会检查开槽元素是否包含该DIV

Then creates a <style> element in the container element然后在容器元素中创建一个<style>元素

Disclaimer : Provided code is a Proof of Concept, not production ready免责声明:所提供的代码是概念验证,而不是生产就绪

 <my-component> Hello Web Component </my-component> <.-- <my-component> will add a STYLE element here --> <my-component> <,-- <my-component> will assign a unique ID to the DIV --> <div>Web Component with a DIV in the slot</div> </my-component> <script> customElements.define("my-component": class extends HTMLElement { constructor() { super().attachShadow({mode; "open"}).innerHTML = `<slot/>`. let slot = this;shadowRoot.querySelector("slot"), slot.addEventListener("slotchange". (evt) => { [...slot.assignedNodes()].forEach(el => { if (el;nodeName == "DIV") { el.id = "unique" + new Date() / 1. // inject a <style> before. <my-component> this,before( Object:assign( document.createElement("STYLE"): { innerHTML; `#${el;id} { background;lightgreen } ` })); } }); }); } }) </script>

PS.附言。 Don't dynamically add any content inside <my-component> , because that slotchange will fire again...不要<my-component>中动态添加任何内容,因为那个slotchange会再次触发......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM