javascript - 与自定义 HTML 元素共享样式?

标签 javascript html css custom-element

我开始使用自定义元素,但我无法弄明白的一件事是共享样式。例如,如果我有 2 个自定义元素,<element-1><element-2> , 两者都包含 <button>的,我希望所有按钮都具有特定的样式,例如font-size:20px .

我考虑过的选项是:

  1. 使用 <stylized-button>自定义元素而不是 <button>在自定义元素中。这在外部采购时会出现问题 <element-1> .如果您还想要其他样式(例如 color:red )也有问题,仅 <element-1>按钮而不是<element-2>按钮。

  2. 据我从 polymer 的文档 [1] 中得知,polymer 也没有针对此问题的解决方案。

  3. /dead/:shadow看起来很有希望,但不再受支持。

  4. 同样@apply [2] 看起来很有希望,但该提议被撤回。

  5. ::part::theme [3] 似乎更有希望,但尚未得到支持。

  6. 使用js支持::part::theme [4].我想如果不解决所有问题,这将非常脆弱。

  7. 将共享样式显式添加到每个自定义元素。

     class Element1 extends HTMLElement {
         constructor() {
             this.shadowRoot.addElement(sharedStyle);
         }
     }
    

    这似乎非常受限和手动。也可能影响性能?如果您从外部采购也有问题 <element-1> .

现在,我认为 #6 可能是最好的,因为它似乎是最通用/最容易使用的,无需专门为其构建,而且在实现后,它会使向 #5 的过渡变得微不足道。 但我想知道是否有其他的方法或建议?

[1] https://www.polymer-project.org/3.0/docs/devguide/style-shadow-dom

[2] http://tabatkins.github.io/specs/css-apply-rule/

[3] https://meowni.ca/posts/part-theme-explainer/

[4] 一个简单的实现和一个使用它的例子:https://gist.github.com/mahhov/cbb27fcdde4ad45715d2df3b3ce7be40

实现:

document.addEventListener('DOMContentLoaded', () => {
    // create style sheets for each shadow root to which we will later add rules
    let shadowRootsStyleSheets = [...document.querySelectorAll('*')]
        .filter(element => element.shadowRoot)
        .map(element => element.shadowRoot)
        .map(shadowRoot => {
          shadowRoot.appendChild(document.createElement('style'));
          return shadowRoot.styleSheets[0];
        });

    // iterate all style rules in the document searching for `.theme` and `.part` in the selectors.
    [...document.styleSheets]
        .flatMap(styleSheet => [...styleSheet.rules])
        .forEach(rule => {
          let styleText = rule.cssText.match(/\{(.*)\}/)[1];

          let match;
          if (match = rule.selectorText.match(/\.theme\b(.*)/))
            shadowRootsStyleSheets.forEach(styleSheet => styleSheet.addRule(match[1], styleText));
          else if (match = rule.selectorText.match(/\.part\b(.*)/))
            shadowRootsStyleSheets.forEach(styleSheet => styleSheet.addRule(`[part=${match[1]}]`, styleText));
        });
  });

和用法:

<style>
  .my-element.part line-green {
    border: 1px solid green;
    color: green;
  }

  .theme .line-orange {
    border: 1px solid orange;
    color: orange;
  }

  /*
    must use `.part` instead of `::part`, and `.theme` instead of `::theme`
    as the browser prunes out invalid css rules form the `StyleSheetList`'s. 
  */
</style>

<template id="my-template">
  <p part="line-green">green</p>
  <p class="line-orange">orange</p>
</template>

<my-element></my-element>

<script>
  customElements.define('my-element', class extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({mode: 'open'});
      const template = document.getElementById('my-template').content.cloneNode(true);
      this.shadowRoot.appendChild(template);
    }
  });
</script>

最佳答案

您可以使用 @import url将外部样式表导入不同的自定义元素。

或者现在您还可以使用 <link rel="stylesheet">在自定义元素 Shadow DOM 中:

<template id="element-1">
  <style> 
      @import url( 'button-style.css' )
  </style>
  <button>B-1</button>
</template>

<template id="element-2">
  <link rel="stylesheet" href="button-style.css">
  <button>B-2</button>
</template>

关于javascript - 与自定义 HTML 元素共享样式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53089691/

相关文章:

javascript - 带有静态方法的 NodeJS 导出类

javascript - 剑道网格错误 - grid.select 不是函数,为什么?

html - 创建响应式眼睛焦点图标

html - 在 div 之外制作 "Close"按钮

javascript - Discord.js - 允许在特定 channel 中执行命令

javascript - DOM 的 JavaScript 解析器

android - 将本地文件夹中的 html 文件加载到 webview 中

html - 固定元素在视差元素内滚动

asp.net - 如何在不与非固定内容重叠的情况下显示标题内容

css - z 索引和相对位置