【问题标题】:How can I style elements used to construct custom elements?如何对用于构造自定义元素的元素进行样式设置?
【发布时间】:2019-01-13 03:22:03
【问题描述】:

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 具有样式,但是 my-element 中使用的 span 不是。甚至在样式表中说my-element span {font-weight: bold;} 也不会使任何样式生效。

有什么方法可以将样式应用到这个span

【问题讨论】:

标签: javascript css custom-element


【解决方案1】:

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

您只能在 shadow 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>

【讨论】:

【解决方案2】:

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

下面的 sn-p 就是这样做的。样式被保存到一个变量中,但您可以将它放在任何地方,只要您知道它的上下文运行的频率。按照 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>

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

我写了一个答案here,所以我会发布一个回答你问题的sn-p:

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>

【讨论】:

    猜你喜欢
    • 2017-08-03
    • 1970-01-01
    • 2023-03-18
    • 2023-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    相关资源
    最近更新 更多