开发中,还是会遇到须要引入内部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 属性的元素。

示例代码

HTML

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

CSS

whats-up::part(sup) {  /* 款式作用于 `sup` 局部 */}whats-up::part(foo) {  /* 款式作用于 `foo` 局部 */}

长处:简洁明了
毛病:兼容性不太好,点击查看caniuse。

三、var

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

JS

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>`;

CSS

whats-up {  --background: #1E88E5;  --color: white;  --padding: 2rem 4rem;  --font-size: 1.5rem;}

长处:兼容性好
毛病:比拟局限,只能内部定几个,款式不能“自在翱翔”

四、通过属性传入

示例代码

JS

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>      `;  }}

HTML

<whats-up  css="    .name{      color: red;    }  "></whats-up>

长处:款式能够随便批改
毛病:代码不够优雅

五、自定义组件外部定义批改款式函数

示例代码

JS

class Whatsup extends HTMLElement {  // ...  // 外围代码  reStyle(els, styles) {    const elements = Array.isArray(els) ? els : [els];    elements.forEach((element) => Object.assign(element.style, styles));  }}

HTML

<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 内部设置款式

示例代码

JS

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);

HTML

<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。

总结

各种办法实用场景各不相同,小心食用。