【问题标题】:User's style for vanilla JS webcomponentvanilla JS webcomponent 的用户样式
【发布时间】:2017-01-03 17:33:09
【问题描述】:

我有这个组件:

index.html

<html>

<head>
    <title></title>
    <meta charset="UTF-8">
    <script src="clock.js"></script>
    <style>
        clock-digital div {
            background-color: green;
        }
    </style>
</head>

<body>
    <clock-digital></clock-digital>
</body>

</html>

clock.js

customElements.define('clock-digital', class extends HTMLElement {

    constructor() {
        super();
        var shadowRoot = this.attachShadow({
            mode: 'open'
        });
        this._clockID = setInterval(function () {
            var currentdate = new Date();
            var hours = ( (currentdate.getHours() < 10) ? '0' : '') + currentdate.getHours();
            var minutes = ( (currentdate.getMinutes() < 10) ? '0' : '') + currentdate.getMinutes();
            var seconds = ( (currentdate.getSeconds() < 10) ? '0' : '') + currentdate.getSeconds();
            shadowRoot.innerHTML = `
            <style>
                div {
                    display: inline-block;
                    width: 65px;
                    text-align: center;
                    background-color: whitesmoke;
                    font-style: italic;
                    border: 1px solid lightgray;
                    border-radius: 3px;
                    box-shadow: 2px 2px 3px;
                }
            </style>
            <div>
                ${hours}:${minutes}:${seconds}
            </div>`;
        }, 500);
    }

});

我希望组件的用户可以在时钟上定义他的样式。我试过了:

<style>
        clock-digital div {
            background-color: green;
        }
    </style>

但它不起作用。我应该在影子根的某处使用插槽标签吗?实现这一目标的最佳做法是什么?

【问题讨论】:

    标签: javascript web-component shadow-dom custom-element


    【解决方案1】:

    您可以在您的自定义元素中公开CSS properties,该元素可以在外部设置。

    在您的示例中,您的元素可以定义--clock-background-color,它设置div 的背景颜色:

    shadowRoot.innerHTML = 
      `<style>
         div {
           background-color: var(--clock-background-color, whitesmoke);
           /* ... */
         }
       </style>
       <div>
         ${hours}:${minutes}:${seconds}
       </div>`;
    

    然后,您的元素的用户可以使用以下命令将背景颜色更改为绿色:

    <style>
      clock-digital {
        --clock-background-color: green;
      }
    </style>
    <clock-digital></clock-digital>
    

    codepen

    请注意,Codepen 演示使用 Web Components polyfills 用于非 Chrome 浏览器,但您可以将其注释掉以查看它在 Chrome 中仍然可以正常工作。

    【讨论】:

    • 这是一个非常优雅的解决方案,我不知道自定义 CSS 属性。谢谢。
    • @asv 没问题 :)
    【解决方案2】:

    您还可以利用用户定义的 CSS 规则优先于代表 Shadow DOM 根(即自定义元素本身)的 :host 选择器。

    在您的自定义元素中,使用:host 设置内容样式:

    shadowRoot.innerHTML = `
        <style>
            :host {
                display: inline-block;
                width: 65px;
                text-align: center;
                background-color: whitesmoke;
                font-style: italic;
                border: 1px solid lightgray;
                border-radius: 3px;
                box-shadow: 2px 2px 3px;
            }
        </style>
        <div>
            ${hours}:${minutes}:${seconds}
        </div>`
    

    现在用户可以使用标准 CSS 符号定义自己的样式,就像任何 HTML 元素一样。这将覆盖:host 规则定义的样式。

    <style>
         clock-digital {
             background-color: green;
             color: white;
         }
    </style>
    

    customElements.define('clock-digital', class extends HTMLElement {
        constructor() {
            super();
            var shadowRoot = this.attachShadow({ mode: 'open' });
            this._clockID = setInterval(function () {
                var currentdate = new Date();
                var hours = ('0'+currentdate.getHours()).substr(-2,2)
                var minutes = ('0'+currentdate.getMinutes()).substr(-2,2)
                var seconds = ('0'+currentdate.getSeconds()).substr(-2,2) 
                shadowRoot.innerHTML = `
                <style>
                    :host {
                        display: inline-block;
                        width: 65px;
                        text-align: center;
                        background-color: whitesmoke;
                        font-style: italic;
                        border: 1px solid lightgray;
                        border-radius: 3px;
                        box-shadow: 2px 2px 3px;
                    }
                </style>           
                ${hours}:${minutes}:${seconds}`;
            }, 500);
        }
    });
    clock-digital  {
      background-color: green;
      color: white;
      font-weight: bold;
    }
    &lt;clock-digital&gt;&lt;/clock-digital&gt;

    【讨论】:

    • 好的,这也很好。有最佳实践吗? :主机或自定义属性css?如果我希望用户不仅可以访问影子的根,还可以访问根的部分子节点,我该如何实现?
    • 没有最佳实践,只有经过调整的解决方案 :-) 我想说:host 更适合简单的自定义元素(如您的问题),自定义属性可以解决更复杂的情况(如您的评论) .您还可以使用其他解决方案,例如属性或样式导入。它还取决于目标平台(Edge 还不支持自定义属性)。
    • 请注意,如果您想让用户为您的自定义元素的所有内容设置样式,您可以使用普通 DOM 而不是 Shadow DOM。它也是有效的“普通”Web 组件。
    • 是的,但是在那种情况下,我的样式可以改变其他用户标签的样式,我不再拥有 shadow DOM 的 scope 属性。如果我没记错的话。
    • 如果您的所有样式规则都以自定义元素的名称开头,则不会。
    猜你喜欢
    • 2018-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-03
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 2017-10-04
    相关资源
    最近更新 更多