在同一类型的网络组件之间共享样式

10
如果我理解正确的话,创建一个 web 组件实例可以概括为创建一个 shadow root 并将标记复制到其中,例如从模板中复制:
var Template = document.querySelector('#myTemplate');
var TemplateClone = document.importNode(Template.content,true);
TargetElement.appendChild(TemplateClone);

当然,如果模板中包含style标签内的css规则,它们也会被复制。因此我们可以拥有属于Web组件内部标记的封闭式样式。

问题:

  1. 如果我创建了大量相同的 Web 组件实例,由于样式只是被复制而不是被重用,这是否会对性能产生影响?
  2. 是否有一种方法可以在多个相同 Web 组件实例之间共享样式节点?

2
刚刚更新了答案,以反映声明影子 DOM 样式表的新方法:https://dev59.com/sp3ha4cB1Zd3GeqPOxWM#40984891 - Harshal Patil
1个回答

10

它会对性能有任何影响吗...?

是的,这取决于有多少个实例以及浏览器中实现的CSS引擎。您将不得不测试每个用例并考虑速度与内存消耗。

有办法在多个相同Web组件实例之间共享样式节点吗?

是的,您可以像这个SO问题中那样使用@import url。或者,您可以选择不使用Shadow DOM,仅使用全局CSS样式。

2019更新

如Harshal Patil所建议,自Chrome 73和Opera 60以来,多个Shadow DOM可以采用相同的样式表。这样,对样式表的更新将应用于所有Web组件。

let css = new CSSStyleSheet
css.replaceSync( `div { color: red }` )

customElements.define( 'web-comp', class extends HTMLElement {
    constructor() {
        super()
        let shadow = this.attachShadow( { mode: 'open' } )
        shadow.innerHTML = `<div><slot></slot></div>`
        shadow.adoptedStyleSheets = [ css ]
    }
} )
color.oninput = () => css.replaceSync( `div { color: ${color.value} }` )
<web-comp>Hello</web-comp>
<web-comp>World</web-comp>
<input value=red id=color>


1
难道它在标记中仍然是重复的,只是不同的是它是从外部URL加载的(当然,结果会被缓存)吗? - Michael K
1
是的,标记不会重复,但是stylesheet对象会被添加到元素的DOM中。无论如何,DOM中的每个元素都会单独进行样式设置,因此元素越多(和样式越多),样式设置过程就会变得更长,无论样式是否共享。我不知道复制的样式表的开销是多少,但也许并不多。它应该随着使用情况(以及CSS引擎实现)而有所不同。 - Supersharp
1
重要提示:以上代码需要 Chrome 73 版本。该版本将于 2019年3月12日 正式发布,因此您现在需要在Chrome开发者版中打开此示例(当前时间为2月23日)。 - Danny '365CSI' Engelman
@Supersharp,我建议在代码示例中将“onchange”更改为“oninput”,这会为HTML颜色名称提供更即时的反馈。 - Danny '365CSI' Engelman
原来 CSS 的 @import url 确实会构建完整的 CSSOM。我建议在部署时进行处理,以最小化打印到组件中的 CSS,避免过多的 RAM 使用,直到采用样式表成为普遍做法。 - Simon
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接