Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 与自定义HTML元素共享样式?_Javascript_Html_Css_Custom Element - Fatal编程技术网

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

Javascript 与自定义HTML元素共享样式?,javascript,html,css,custom-element,Javascript,Html,Css,Custom Element,我开始使用自定义元素,但有一件事我搞不清楚,那就是共享样式。例如,如果我有两个自定义元素,和,它们都包含,并且我希望所有按钮都具有特定的样式,例如字体大小:20px 我考虑过的选项有: 使用自定义元素,而不是自定义元素中的。当外部采购时,这是有问题的。如果只在按钮上而不在按钮上使用其他样式(例如颜色:红色),也会出现问题 根据polymer的文档[1],polymer也没有解决方案 /dead/和:shadow似乎很有希望,但不再受支持 同样地,@apply[2]似乎很有希望,但提案被撤回 ::

我开始使用自定义元素,但有一件事我搞不清楚,那就是共享样式。例如,如果我有两个自定义元素,
,它们都包含
,并且我希望所有按钮都具有特定的样式,例如
字体大小:20px

我考虑过的选项有:

  • 使用
    自定义元素,而不是自定义元素中的
    。当外部采购
    时,这是有问题的。如果只在
    按钮上而不在
    按钮上使用其他样式(例如
    颜色:红色),也会出现问题

  • 根据polymer的文档[1],polymer也没有解决方案

  • /dead/
    :shadow
    似乎很有希望,但不再受支持

  • 同样地,
    @apply
    [2]似乎很有希望,但提案被撤回

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

  • 使用js支持
    ::part
    ::theme
    [4]。我想如果不把所有的箱子都熨平,这件衣服会很脆

  • 显式地将共享样式添加到每个自定义元素

    class Element1 extends HTMLElement {
        constructor() {
            this.shadowRoot.addElement(sharedStyle);
        }
    }
    
    这似乎非常受限&手动。还会影响性能吗?如果您从外部采购
    ,也会出现问题

  • 现在,我认为#5可能是最好的,因为它似乎是最通用/最容易使用的,而无需专门为它构建,而且它在实现时会使转换到#4变得很简单但我想知道是否还有其他方法或建议?

    [1]

    [2]

    [3]

    [4] 一个简单的实现和一个使用它的示例:

    实施:

    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>
    
    
    .my-element.part行绿色{
    边框:1px纯绿色;
    颜色:绿色;
    }
    .主题.橙色线条{
    边框:1px实心橙色;
    颜色:橙色;
    }
    /*
    必须使用“.part”而不是“::part”,必须使用“.theme”而不是“::theme”`
    当浏览器从“样式表列表”中删除无效的css规则时。
    */
    绿色

    橙色

    定义('my-element',类扩展HtmleElement{ 构造函数(){ 超级(); this.attachShadow({mode:'open'}); const template=document.getElementById('my-template').content.cloneNode(true); this.shadowRoot.appendChild(模板); } });
    您可以使用
    @import url
    将外部样式表导入到不同的自定义元素中

    或者,现在您也可以在自定义元素阴影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>
    
    
    @导入url('button style.css')
    B-1
    B-2
    
    如果您使用的是css,您可以这样做:

    button {
    
      /* Put Style Here */  
    
    }
    
    您还必须在html的头部添加一个链接:

    <link rel=“stylesheet” href=“the address”>
    
    
    
    只是想知道:跨浏览器功能对你来说有多重要?好的一点,我忘了提到,就我的使用案例而言,我只关心最新版本的chrome。另请参阅本文:这似乎相当于#7,并且有同样的缺点;e、 g.如果元素2是由依赖项定义的,我将无法使用此方法设置其按钮的样式。但我实际上是在一个项目上尝试这个方法(所有元素都是我的),而且效果很好。我不明白你说的depency,一个第三方自定义元素是什么意思?是的,这是一个限制,但它正是shadow dom功能的目的和预期行为。是的,这就是我所说的依赖性,尽管它可能不是第三方,而是您自己的通用元素包,您希望通过不同的样式重复使用。我不同意这是“目的和预期行为”,这更多的是在执行上的滞后。过去肯定有人尝试用shadow元素来支持这一点(例如/deep/,:shadow和@apply),将来肯定有计划支持(例如::part和::theme),chrome至少正在积极地开发这一功能。不同的尝试由于多种原因(缓慢、无法实现、危险……)而失败. ::part and::theme不会与第三方库一起使用,而且不会很快推出(仍然没有alpha版本)。自定义属性(或自定义实现)是唯一的备选方案(与答案中的限制相同或更多)。这就是为什么说CSS隔离是ShadowDOM的目的是现实的。如果您想要全局样式,我建议您设计没有阴影DOM的自定义元素。有趣的建议是,我在网上发现很少有资源使用没有阴影dom的自定义元素,所以我认为这是一种不好的做法。我将尝试一下我的用例,看看是否有任何问题出现。全局样式不会应用于阴影DOM中