【问题标题】:CSS not working properly on Custom HTML ElementsCSS 在自定义 HTML 元素上无法正常工作
【发布时间】:2022-01-26 04:06:06
【问题描述】:

我一直在尝试通过扩展 HTMLElement 类来制作自定义 HTML 元素。我尝试通过链接与我的其他两个文件位于同一目录中的 CSS 文件来添加一些样式 - index.htmlcustom.css

主文件夹

  • index.html
  • custom.css
  • custom.js

index.html:

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="nofollow" type="text/css" href=''>
</head>
 
    <body>
        <script src="./custom.js"></script>
        <smooth-button text="Smooth button" no-1 = 1 no-2 = 2></smooth-button>
    </body>
 
</html>

custom.css:

smooth-button{
    display: block;
    color: blue;
    background-color: orange;
}

custom.js:

class SmoothButton extends HTMLElement{
 
    constructor(){
        super();
        this.shadow = this.attachShadow({mode: "open"})
    }
 
    connectedCallback(){
        this.render();
    }
 
    render(){
        this.SumOfNo1AndNo2 = null;
        if(this.getAttribute("no-1")!=null && this.getAttribute("no-2")!=null){
            this.SumOfNo1AndNo2 = parseInt(this.getAttribute("no-1")) + 
            parseInt(this.getAttribute("no-2"));
        }
        else{
            console.log("Invalid attribute.")
        }
        this.shadow.innerHTML = `<button>` + this.getAttribute("text") + " " + this.SumOfNo1AndNo2   
        + "</button>"
    }
 
}
 
customElements.define("smooth-button", SmoothButton);  

这样,我按预期得到了一个带有文本的按钮,但样式应用于整个元素,而不是构成它的元素。如何使用外部 CSS 文件将样式分别应用于其每个元素(现在只是 &lt;button&gt;)?我正在使用外部 CSS,因为我阅读它时感觉更好here

【问题讨论】:

  • 不管怎样,你有一些无效的 HTML。确保引用您的属性值 no-1no-2

标签: javascript html css shadow-dom custom-element


【解决方案1】:

除了 Brad 和 Emiel 的回答之外,

  • (Brad) 直接在 shadowDOM 中添加一个&lt;style&gt; 元素
  • (Emiel)使用级联 CSS 属性
  • 还有更多设置 shadowDOM 样式的选项:

了解可继承样式

使用阴影部分

<style>
  ::part(smoothButton){
    display: block;
    color: blue;
    background-color: orange;
  }
</style>

<smooth-button></smooth-button>
<smooth-button></smooth-button>

<script>
  customElements.define("smooth-button", class extends HTMLElement {
    constructor(){
      super()
        .attachShadow({mode:"open"})
        .innerHTML = `<button part="smoothButton">LABEL</button>`;
    }
  });
</script>

但是……

你应该问自己的第一个问题:

我真的需要 shadowDOM 吗?

如果你不想要它的封装行为,那么不要使用 shadowDOM

<style>
  .smoothButton{
    display: block;
    color: blue;
    background-color: orange;
  }
</style>

<smooth-button></smooth-button>
<smooth-button></smooth-button>

<script>
  customElements.define("smooth-button", class extends HTMLElement {
    connectedCallback(){
      this.innerHTML = `<button class="smoothButton">LABEL</button>`;
    }
  });
</script>

shadowDOM &lt;slot&gt;

另一种选择是使用 shadowDOM &lt;slot&gt; 元素,因为它们由其容器元素设置样式

<style>
  .smoothButton{
    display: block;
    color: blue;
    background-color: orange;
  }
</style>

<smooth-button><button class="smoothButton">LABEL</button></smooth-button>
<smooth-button><button class="smoothButton">LABEL</button></smooth-button>

<script>
  customElements.define("smooth-button", class extends HTMLElement {
    constructor(){
      super()
        .attachShadow({mode:"open"})
        .innerHTML = `<slot></slot>`;
    }
  });
</script>

当您进入&lt;slot&gt;rabbithole 时,请务必阅读(非常长的)帖子:
::slotted CSS selector for nested children in shadowDOM slot

【讨论】:

    【解决方案2】:

    除了布拉德的回答。将 Light DOM 中的样式应用到 Shadow DOM 的方法之一是使用 CSS 变量。

    smooth-button{
      display: block;
    
      --button-color: blue;
      --button-background-color: orange;
    }
    
    render() {
      this.shadow.innerHTML = `
        <style>
          button {
            color: var(--button-color);
            background-color: var(--button-background-color);
          }
        </style>
    
        <button>
          ${this.getAttribute("text")} ${this.SumOfNo1AndNo2}   
        </button>
      `;
    )
    

    【讨论】:

    • 非常感谢您的回答!只是问 - 有没有办法使用代码(不依赖于浏览器)缓存文件(.txt 文件?)?有没有办法获取缓存文件(使用代码)?
    • 不客气。对于新问题,请在 SO 中打开一个新问题,但现在:您可以结合使用 Cache APIService Worker API 来缓存客户端请求的任何文件。
    【解决方案3】:

    这样,我按预期得到了一个带有文本的按钮,但样式应用于整个元素,而不是构成它的元素。

    这实际上是自定义元素的工作方式。您不能将样式应用于外部文档中的影子 DOM。如果可以,您很可能会通过外部修改破坏自定义元素样式。

    然而,一切都没有丢失!按钮与其背景颜色不同的原因是由于用户代理样式表。您实际上可以设置一些 CSS 来告诉背景继承父背景颜色。尝试将此添加到您的自定义元素中:

    const style = document.createElement('style');
    style.textContent = `
      button {
        background: inherit;
      }
    `;
    this.shadow.append(style);
    

    JSFiddle:https://jsfiddle.net/5t2m3bku/

    (另请注意,将文本直接插入/连接到 HTML 中并不是一个好主意。该文本会被解释为 HTML,如果使用保留字符,可能会导致 HTML 无效,甚至潜在的 XSS 漏洞。您可以修改设置 innerHTML 以设置文本或切换到模板引擎的那一行。)

    【讨论】:

      猜你喜欢
      • 2017-03-25
      • 2013-11-02
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 2016-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多