3

Web Components中引入外部CSS的 8 种方法

 2 years ago
source link: https://segmentfault.com/a/1190000040915602
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

开发中,还是会遇到需要引入外部CSS到Shadow DOM情况,那么如何处理呢?作者就最近遇到的情况给出如下几种方案。

一、@import

const template = document.createElement('template');

class WhatsUp extends HTMLElement {
  connectedCallback() {
    const shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.innderHTML = `
      <style>
          @import "./index.css"; // 核心代码
      </style>
      <div>Sup</div>
    `
  }
}

window.customElements.define('whats-up', WhatsUp);

优点:此方法兼容性非常好,点击查看caniuse
缺点:性能

二、::part

::part CSS 伪元素表示在阴影树中任何匹配 part 属性的元素。

<template id="whats-up">
    <div part="sup">Sup</div>
    <div part="foo">Sup</div>
</template>

<whats-up></whats-up>
whats-up::part(sup) {
  /* 样式作用于 `sup` 部分 */
}
whats-up::part(foo) {
  /* 样式作用于 `foo` 部分 */
}

优点:简洁明了
缺点:兼容性不太好,点击查看caniuse

三、var

CSS自定义属性可以穿透到 Shadow DOM中!
示例代码

const template = document.createElement('template');
template.innerHTML = `
<style>
button {
  background: var(--background);
  color: var(--color);
  padding: var(--padding);
  font-size: var(--font-size);
  border: 0;
}
</style>
<div>Sup</div>`;
whats-up {
  --background: #1E88E5;
  --color: white;
  --padding: 2rem 4rem;
  --font-size: 1.5rem;
}

优点:兼容性好
缺点:比较局限,只能外部定几个,样式不能“自由飞翔”

四、通过属性传入

class Whatsup 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">Sup</div>
      `;
  }
}
<whats-up
  css="
    .name{
      color: red;
    }
  "
></whats-up>

优点:样式可以随意修改
缺点:代码不够优雅

五、自定义组件内部定义修改样式函数

class Whatsup extends HTMLElement {
  // ...

  // 核心代码
  reStyle(els, styles) {
    const elements = Array.isArray(els) ? els : [els];
    elements.forEach((element) => Object.assign(element.style, styles));
  }
}
<whats-up></whats-up>

<script>
    const myEle = document.querySelector('whats-up')
    const title = myEle.shadowRoot.querySelector('.title');

    myEle.reStyle(title, {
        color: 'red',
        width: '200px',
    })
</script>

六、通过 slot 外部设置样式

class WhatsUp extends HTMLElement {
  constructor() {
    super();
    const shadowRoot = this.attachShadow({ mode: 'open' });
    shadowRoot.innerHTML = `
    <div>
      <slot name="header"></slot>
    </div>
    `;
  }
}
customElements.define('whats-up', WhatsUp);
<style>
  .header{
    color: red;
  }
</style>

<whats-up>
  <div slot="header" class="header">
    what's up
  </div>
</whats-up>

七、fetch获取

class WhatsUp extends HTMLElement {
  constructor() {
    super();
    const shadowRoot = this.attachShadow({ mode: 'open' });
    // 获取样式
    fetch('./index.css').then(res => res.text()).then(data => {
        let node = document.createElement('style');
        node.innerHTML = data;
        this.shadowRoot.appendChild(node);
    });
    // ...
  }
}
customElements.define('whats-up', WhatsUp);

优点:优点是兼容性不错,支持Shadow DOM的元素均支持此语法;以及性能还OK
缺点:不优雅

八、CSS module import

此方法使用浏览器原生的import语法,但是import的是CSS文件而不是JS文件。
也就是把CSS文件直接作为模块引入。
示例代码

import styles from "index.css";

class WhatsUp extends HTMLElement {
  constructor() {
    // ...
    // 核心代码
    shadow.adoptedStyleSheets = [styles];
  }
}

优点:优点是使用方便快捷且是官方推荐方法,或者是import CSS模块就是为了这个场景才支持的;以及性能OK,import本身就是异步过程。
缺点:兼容性不佳,狠狠戳这里caniuse

各种方法适用场景各不相同,小心食用。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK