如何设置用于构造自定义元素的元素的样式?

时间:2019-01-13 03:22:04

标签: javascript css custom-element

class MyElement extends HTMLElement {
    constructor() {
        super()
        const shadow = this.attachShadow({mode: 'open'})
        shadow.appendChild(document.createTextNode('Yadda blah'))
        const span = document.createElement('span')
        span.appendChild(document.createTextNode('Can I style U?'))
        shadow.appendChild(span)
    }
}
customElements.define('my-element', MyElement)
my-element {
    border: 1px solid black;
}

span {
    font-weight: bold;
}
<my-element></my-element>

如您所见,my-element具有样式,但是span中使用的my-element没有样式。甚至在样式表中说my-element span {font-weight: bold;}都不会使任何样式有效。

是否可以将样式应用于此span

2 个答案:

答案 0 :(得分:1)

这是影子dom的预期行为。由于您的HTML看起来像<my-element></my-element>,因此可以从CSS定位my-element,但是span并不是实际dom的一部分,因此您无法定位它。

您只能在阴影dom上下文中将样式应用于span

在这种情况下,有更好的方法来定义css,但是为了说明一点,以下内容将样式应用于span,而不是my-element

class MyElement extends HTMLElement {
    constructor() {
        super()
        const shadow = this.attachShadow({mode: 'open'})
        shadow.appendChild(document.createTextNode('Yadda blah'))
        const span = document.createElement('span')
        span.appendChild(document.createTextNode('Can I style U?'))
        shadow.appendChild(span)
        const styleTag = document.createElement('style')
        styleTag.innerHTML = `
            my-element {
                border: 1px solid black;
            }
            span {
                font-weight: bold;
            }
        `
        shadow.appendChild(styleTag)
    }
}
customElements.define('my-element', MyElement)    
<my-element></my-element>

答案 1 :(得分:0)

您必须将样式应用于阴影DOM。一种常见但即将过时的技术是在阴影DOM中添加一个<style>元素,并将其文本内容设置为您要在自定义元素中应用的CSS。

下面的代码片段就是这样做的。样式保存到变量中,但是只要您知道其上下文运行的频率,就可以将其放置在任何位置。遵循Intervalia的建议,最好使用:host将样式应用于自定义元素。

也可以改为添加<link>元素,但这可能会导致该元素弹出而没有样式(FOUC

const myElementStyle = `
:host {
    border: 1px solid black;
}
span {
    font-weight: bold;
}
`

class MyElement extends HTMLElement {
    constructor() {
        super()
        const shadow = this.attachShadow({mode: 'open'});
        const style = document.createElement('style');
        style.textContent = myElementStyle;
        shadow.appendChild(style);
        
        shadow.appendChild(document.createTextNode('Yadda blah'));
        const span = document.createElement('span');
        span.appendChild(document.createTextNode('Can I style U?'));
        shadow.appendChild(span);
    }
}
customElements.define('my-element', MyElement)
<my-element></my-element>

另一种选择是使用可构造样式表,该样式表应很快在现代浏览器中可用。这些使您可以创建一个样式表对象,该对象可以嵌入样式或从外部资源导入样式。

我写了一个答案here,所以我只发布一个片段来回答您的问题:

const customSheet = new CSSStyleSheet();
customSheet.replaceSync(`
:host {
  border: 1px solid black;
}
span {
  font-weight: bold;
}
`);

class MyElement extends HTMLElement {
  constructor() {
    super()
    const shadow = this.attachShadow({
      mode: 'open'
    })

    shadow.adoptedStyleSheets = [customSheet];

    shadow.appendChild(document.createTextNode('Yadda blah'))
    const span = document.createElement('span')
    span.appendChild(document.createTextNode('Can I style U?'))
    shadow.appendChild(span)
  }
}
customElements.define('my-element', MyElement)
<my-element></my-element>