如何将 Shadow Dom 与 Javascript 和 CSS 模块一起使用

How to use Shadow Dom with Javascript and CSS modules

提问人:McMurphy 提问时间:11/4/2023 最后编辑:McMurphy 更新时间:11/6/2023 访问量:82

问:

编辑 1

非常感谢@Danny提供的非常有用的答案。我想我的问题更多地与 CSS sope 和封装有关。如果我将 CSS 样式表导入模块,那么我不希望该样式表渗入调用者的父级和 lightDOM。我想要达到的效果类似于这个基本的自定义元素:在本例中,我构建了一个 STYLE 元素并将其附加到 HTMLElement 的 Extension 类。

我正在尝试使用 Javascript/CSS 模块实现同样的事情。我将尝试使用 myDiv.part='shadowTree',但这似乎违背了 ShadowDOM 的全部目的。

我会再次阅读 om SLOT,但我只想公开我的模块调用中的某些元素。这就是我认为的 #returnedDiv::p art(styleableRuleException) 是什么,我希望将 CSS 的其余部分强行限定为我的 JS 模块?

WRT MDN 我认为我的问题是我导入的样式表不是“构造样式表”?喜欢:-

 let sheet = new CSSStyleSheet();

但是 Web.Dev 说好吗?

<编辑 1

我正在尝试在我的 Javascript 模块中使用 Shadow DOM,并将 CSS 模块/工作表导入 Javascript 模块:-

模块.js

import sheet from '/styles.css' assert {type: 'css'};

export function message()
{
    const myDiv = document.createElement("div");
    const shadowRoot = myDiv.attachShadow({mode:"open"});
    document.adoptedStyleSheets = [sheet];
    myDiv.textContent = "This is Text";
    return myDiv;
}

一旦我将该行添加到 .attachShadow() 中,DIV“This is Text”的内容就停止出现。

如果我更进一步尝试将样式表采用到 shadowRoot 而不是文档,那么 styles.css 中的 CSS 不会生效。

样式 .css

host:: {
    background-color: yellow;
}
div {
    background-color: red;
}

我必须做些什么才能在我的模块中使用 Shadow DOM 与 CSS 模块中的采用样式协同使用?

test_mod.html

<!DOCTYPE html>
<html>
<style type="text/css">
div div {
    height: 100px;
    width: 100px;
    text-align: center;
    background-color: lightblue;
}
</style>
<script type="module">
import {message} from "http://localhost/message.js";

document.getElementById("demo").appendChild(message());

</script>
<body>
<h1>JavaScript Modules</h1>

<div id="demo"></div>

</body>
</html>
javascript css es6-modules shadow-dom

评论


答:

3赞 Danny '365CSI' Engelman 11/4/2023 #1

一旦我将该行添加到 .attachShadow() 中,DIV“This is Text”的内容就停止出现。

因为你在 lightDOM 中设置了内容,这些内容只会在你这样做时显示在 shadowDOM 中。<slot>

如果我更进一步尝试将样式表采用到 shadowRoot 而不是文档,那么 styles.css 中的 CSS 不会生效。

语法不是:hosthost::

请阅读:

这里是一个游乐场,里面有几乎所有的shadowDOM好东西。

JSFiddle:https://jsfiddle.net/WebComponents/bj4n1L0r/

<h1>shadowDOM, loathed but loaded</h1>
<script>
  function adoptSheet(atRoot, styles) {
    let sheet = new CSSStyleSheet();
    sheet.replaceSync(styles);
    atRoot.adoptedStyleSheets.push(sheet);
  }
  // Global CSS
  adoptSheet(document, "h1 { background: hotpink }" +
                       "div { background: pink }" +
                       "div::part(shadowH1) { background: lightgreen }");

  const myDiv = document.createElement("div");
  myDiv.setAttribute("border", "true");
  const shadowRoot = myDiv.attachShadow({ mode: "open" });
  adoptSheet(shadowRoot, ":host { background: red; padding: 5px }" +
                         ":host([border]) { border:2px dashed green }" +
                         "h1 { color: green }" +
                         "::slotted(h1) { color: blue }");

  myDiv.innerHTML =      "<h1                >I am in lightDOM</h1>";
  shadowRoot.innerHTML = "<h1 part='shadowH1'>I am in shadowDOM</h1>" +
                         "<slot>lightDOM will be slotted here</slot>";

  document.body.append(myDiv);
</script>

笔记

  • 全局 CSS 样式 BOTH 在主文档中,因为插槽内容不会移动到 shadowDOM 而是反射到 shadowDOM 请参阅(长读):::slotted CSS 选择器用于 shadowDOM
    插槽中嵌套的子项
    <h1>background:hotpink

  • ::part在全局 CSS 中可以设置 shadowDOM
    中内容的样式 https://developer.mozilla.org/en-US/docs/Web/CSS/::part

  • :host没有特异性,所以 shadowDOM 不是
    这是这样 (web) 组件用户可以覆盖默认样式(参见),如果您不想要,请在 shadowDOM 中添加一个额外的层并设置样式。
    background: redbackground:pink<div>

  • 有两种类型的(Web 组件)开发人员:
    那些抱怨 shadowDOM 的人,以及那些学会掌握 shadowDOM 的人

评论

0赞 McMurphy 11/5/2023
呸!如果 SLOT 不是 Web 组件,为什么需要使用 SLOT?
1赞 Danny '365CSI' Engelman 11/5/2023
因为是 shadowDOM 功能,而不是 Web 组件功能。严格来说,我们称使用 Custom Element 创建的元素,当您添加它们时,它们被称为 Web 组件。每个人都可以互换使用这两个术语。<slot>Custom Elements APIshadowDOM
1赞 Danny '365CSI' Engelman 11/5/2023
你的代码证明你可以没有它。对此没有严格的术语。它是带有 shadowDOM 的原生元素。需要注意的是,所有浏览器厂商都是这样构建的,我们凡人开发者都无法访问那些。所以 shadowDOM 已经存在了大约 12 年。Custom Elements API<input>, <textarea> etc.(user-agent) shadowRootshadowDOM
0赞 McMurphy 11/6/2023 #2

我将丹尼的答案标记为正确,因为它包含大量有用的信息。

事实上,我的一个小学生错误是继续将子元素附加到宿主而不是影子根。

顺便说一句。没想到这里有人会年纪大到能记住功夫:-)

评论

1赞 Danny '365CSI' Engelman 11/6/2023
60 年代的孩子,大卫很酷,但玛西娅布雷迪是我的最爱。