总结 8种前端Web组件中引入外部CSS的方法

49 阅读1分钟

自定义元素的使用:

有两种类型的自定义元素:

  • 自定义内置元素(Customized built-in element)继承自标准的 HTML 元素,例如 HTMLImageElement 或 HTMLParagraphElement。它们的实现定义了标准元素的行为。
  • 独立自定义元素(Autonomous custom element)继承自 HTML 元素基类 HTMLElement。你必须从头开始实现它们的行为。

使用示例:

// 为这个元素创建类
class MyCustomElement extends HTMLElement {
  static observedAttributes = ["color", "size"];

  constructor() {
    // 必须首先调用 super 方法
    super();
  }

  connectedCallback() {
    console.log("自定义元素添加至页面。");
  }

  disconnectedCallback() {
    console.log("自定义元素从页面中移除。");
  }

  adoptedCallback() {
    console.log("自定义元素移动至新页面。");
  }

  attributeChangedCallback(name, oldValue, newValue) {
    console.log(`属性 ${name} 已变更。`);
  }
}

customElements.define("my-custom-element", MyCustomElement);

方法1、@import

    <div>
        <my-custom-element></my-custom-element>
    </div>
    <script>
      class MyCustomElement extends HTMLElement {
        //这是自定义元素的生命周期钩子:每当元素添加到文档中时调用;规范建议开发人员尽可能在此回调中实现自定义元素的设定,而不是在构造函数中实现。
        connectedCallback() {
           const shadowRoot = this.attachShadow({ mode: "open" });
           shadowRoot.innerHTML = `
            <style>
                @import "./index.css"; // 核心代码
            </style>
            <div class="title">我的自定义元素</div>
            `;
        }
      }

      window.customElements.define("my-custom-element", MyCustomElement);
    </script>
//index.css文件
.title {
    color: green;
}

方法2、::part

//HTML: 自定义元素内部
<div class="my-custom-element" part="my-custom-element">
	<div part="top">Top</div>
	<div part="bottom">Bottom</div>
</div>

//标签使用
<my-custom-element></my-custom-element>

//CSS: 外部CSS覆盖元素内部样式,part标注唯一标识
my-custom-element::part(top) {
  /* 样式作用于 `top` 部分 */
}
my-custom-element::part(bottom) {
  /* 样式作用于 `bottom` 部分 */
}

方法3、var

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      my-custom-element {
        --background: #1e88e5;
        --color: white;
        --padding: 2rem 4rem;
        --font-size: 1.5rem;
      }

    </style>
  </head>
  <body>
    <div>
        <my-custom-element></my-custom-element>
    </div>
    <script>
      class MyCustomElement extends HTMLElement {
        //这是自定义元素的生命周期钩子:每当元素添加到文档中时调用;规范建议开发人员尽可能在此回调中实现自定义元素的设定,而不是在构造函数中实现。
        connectedCallback() {
           const shadowRoot = this.attachShadow({ mode: "open" });
           shadowRoot.innerHTML = `
            <style>
                button {
                    background: var(--background);
                    color: var(--color);
                    padding: var(--padding);
                    font-size: var(--font-size);
                    border: 0;
                }
            </style>
            <div>我的自定义元素</div>
            <button>按钮</button>
        `;
        }
      }

      window.customElements.define("my-custom-element", MyCustomElement);
    </script>
  </body>
</html>

方法4、通过属性传入

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <my-custom-element css=".name{color:red;}"></my-custom-element>
    </div>
    <script>
      class MyCustomElement extends HTMLElement {
        static get observedAttributes() {
          return ["css"];
        }

        constructor() {
          super();
        }

        get css() {
          return this.getAttribute("css");
        }

        set css(value) {
          if (value === null || value === false) {
            this.removeAttribute("css");
          } else {
            this.setAttribute("css", value);
          }
        }

        connectedCallback() {
          const shadowRoot = this.attachShadow({
            mode: "open",
          });
          shadowRoot.innerHTML = `
            <style>
              :host{
                display: flex;
              }
              ${this.css} // 核心代码
            </style>
            <div class="name">我的自定义元素</div>
          `;
        }
      }

      window.customElements.define("my-custom-element", MyCustomElement);
    </script>
  </body>
</html>

方法5、自定义组件内部定义修改样式函数

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <my-custom-element></my-custom-element>
    </div>
    <script>
      class MyCustomElement extends HTMLElement {
        // 核心代码
        reStyle(els, styles) {
          const elements = Array.isArray(els) ? els : [els];
          elements.forEach((element) => Object.assign(element.style, styles));
        }

        connectedCallback() {
          const shadowRoot = this.attachShadow({ mode: "open" });
          shadowRoot.innerHTML = `
            <style>
                .title {
                    background: green;
                }
            </style>
            <div class="title">我的自定义元素</div>
            `;
        }
      }

      window.customElements.define("my-custom-element", MyCustomElement);
    </script>

    <script>
      const myEle = document.querySelector("my-custom-element");
      const title = myEle.shadowRoot.querySelector(".title");

      myEle.reStyle(title, {
        color: "red",
        width: "200px",
      });
    </script>
  </body>
</html>

方法6、通过 slot 外部设置样式

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
        .content{
            color: red;
        }
    </style>
  </head>
  <body>
    <div>
      <my-custom-element>
        <div slot="title" class="content">具体内容</div>
      </my-custom-element>
    </div>
    <script>
      class MyCustomElement extends HTMLElement {
        constructor() {
          super();
          const shadowRoot = this.attachShadow({ mode: "open" });
          shadowRoot.innerHTML = `
            <div>我的自定义元素</div>
            <div>
                <slot name="title"></slot>
            </div>
          `;
        }
      }

      window.customElements.define("my-custom-element", MyCustomElement);
    </script>

    <script></script>
  </body>
</html>

方法7、fetch获取

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <my-custom-element> </my-custom-element>
    <script>
      class MyCustomElement extends HTMLElement {
        constructor() {
          super();
        }

        connectedCallback() {
          const shadowRoot = this.attachShadow({ mode: "open" });
          shadowRoot.innerHTML = `
            <div class="title">我的自定义元素</div>
            `;

          // 获取样式
          fetch("./index.css")
            .then((res) => res.text())
            .then((data) => {
              let node = document.createElement("style");
              node.innerHTML = data;
              this.shadowRoot.appendChild(node);
            });
        }
      }
      window.customElements.define("my-custom-element", MyCustomElement);
    </script>
  </body>
</html>
//index.css文件
div {
    color: red;
}

.title {
    color: green;
}

方法8、CSS module import

//使用浏览器原生的import语法,但是import的是CSS文件而不是JS文件。
//把CSS文件直接作为模块引入。
import styles from "index.css";

class WhatsUp extends HTMLElement {
  constructor() {
  
    shadow.adoptedStyleSheets = [styles];
  }
}

参考文章链接:zhuanlan.zhihu.com/p/436405556

developer.mozilla.org/zh-CN/docs/…