在 Web 组件中使用外部 CSS 链接引用

3

我想在自定义网络组件中使用CDN提供的Bulma,但似乎没有起作用。

这是我的HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>hello</title>
  <meta charset="utf-8">
</head>
<body>
    <my-element></my-element>
    <script src="index.js"></script>

</body>
</html>

以下是我的js文件:

const sheet = new CSSStyleSheet()

sheet.replace('@import url("https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css")');

class MyElement extends HTMLElement {
    connectedCallback(){
        let that = this
        let id = Math.random()
        this.id = id

        const shadowRoot = this.attachShadow({ mode: 'open' })
        shadowRoot.adoptedStyleSheets = [sheet]

        let child = document.createElement('button')
        child.classList.add("button")
        child.innerText = id

        child.id = count

        shadowRoot.appendChild(child)

        this.addEventListener('click', e => {
            e.target
            console.log(that.id)
            that.remove()
        })
    }
}

if(!customElements.get('my-element')){
    customElements.define('my-element', MyElement)
}

let count = Math.floor(Math.random() * 10) + 1
for(i = 0; i <= count; i++){
    let el = document.createElement('my-element')
    document.body.appendChild(el)
}

值得注意的是,如果我使用sheet.replaceSync('button { color: green; }')代替sheet.replace(...),它可以正常工作。但是为什么外部CSS链接引用导入不起作用呢?
更新:我意识到控制台中出现了以下警告:
index.js:6 @import rules are not allowed here. See https://github.com/WICG/construct-stylesheets/issues/119#issuecomment-588352418.

作为注意事项,我正在尝试使用这种方法,以便可以以相同的方式样式多个自定义 Web 组件,而无需多次导入样式表。谢谢!

在Devtools的网络选项卡中是否出现任何Cors错误? - zergski
@zergski - 没有CORS错误,但我刚意识到我收到了一个相关的警告,我已经添加到问题中了。 - Dshiz
我认为 @import 规则不能动态使用,您可以通过将 <link type="stylesheet" href="url"> 添加到文档中来添加样式表。 - zergski
1
顺便提一下,你应该在构造函数中创建阴影DOM,而不是在connectedCallback中创建,因为后者可能会被多次调用(例如每当添加或移动DOM中的元素时)。 - connexo
1
const shadowRoot 这个变量是不必要的。在 this.shadowRoot 实例上始终可用。 - connexo
显示剩余3条评论
1个回答

1

我的方法是为所有组件使用单个实例,类似于这样:

import bulmaStyles from 'https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css';
const bulmaCSS = new CSSStyleSheet;
bulmaCSS.replaceSync(bulmaStyles);

export class Styles {
  static get bulma() { return bulmaCSS }
}

然后,在您的组件中导入这个类

import { Styles } from 'path/to/Styles.js';

class MyElement extends HTMLElement {
    constructor() {
      super();
      // and use it in the constructor after creating the shadow DOM
      this.attachShadow({ mode: 'open' })
      this.shadowRoot.adoptedStylesheets = [ Styles.bulma ];
    }
}

为了将样式表的CSS导入到变量中,您需要构建堆栈支持该功能。Webpack通过使用webpack-raw-loader等方式支持它。
如果您没有捆绑代码,您将不得不等待CSS模块或从DOM中获取样式。

我遇到了这个错误:无法加载模块脚本:服务器响应的 MIME 类型为“text/css”,不是 JavaScript。根据 HTML 规范,模块脚本执行严格的 MIME 类型检查。 - Dshiz
我尝试通过在Styles.js的static get bulma(){...}函数中返回fetch,然后使用bulbmaCSS.replaceSync(bulmaStyles)应用返回的CSS来解决此错误。我可以在我的组件构造函数中看到样式,但是附加到我的自定义元素的子元素没有采用该样式。 - Dshiz
正如提到的那样,直到CSS模块已经落实在规范和浏览器中,你需要使用像webpack这样的构建工具以及 raw-loader 来将CSS导入到Javascript变量中。 - connexo
只是为了再次确认,我没有看到提到浏览器;你知道adoptyedStyleSheets在Firefox和Safari中还不能使用吗?https://caniuse.com/mdn-api_document_adoptedstylesheets - Danny '365CSI' Engelman
1
@Danny'365CSI'Engelman: 火狐浏览器现在支持构建样式表,需要打开标志。在 about:config 中将 layout.css.constructable-stylesheets.enabled 设置为 true - connexo
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接