【发布时间】:2019-04-04 23:50:32
【问题描述】:
我开始使用自定义元素,但我想不通的一件事是共享样式。例如,如果我有 2 个自定义元素 <element-1> 和 <element-2>,它们都包含 <button>,并且我希望所有按钮都具有某种样式,例如font-size:20px.
我考虑过的选项是:
-
在自定义元素中使用
<stylized-button>自定义元素而不是<button>。当外部采购<element-1>时,这是有问题的。如果您还希望仅在<element-1>按钮而不是<element-2>按钮上使用其他样式(例如color:red),也会有问题。 -
据我从聚合物的文档 [1] 中得知,聚合物也没有解决方案。
-
/dead/和:shadow看起来很有希望,但不再受支持。 -
同样
@apply[2] 看起来很有希望,但该提案被撤回了。 -
::part和::theme[3] 似乎更有前途,但尚不支持。 -
使用js支持
::part和::theme[4]。我想如果不解决所有情况,这将非常脆弱。 -
为每个自定义元素显式添加共享样式。
class Element1 extends HTMLElement { constructor() { this.shadowRoot.addElement(sharedStyle); } }这似乎非常受限和手动。还可能影响性能?如果您从外部采购
<element-1>,也会有问题。
现在,我认为#6 可能是最好的,因为它似乎是最通用/最容易使用的,无需专门为它构建,而且在实施时它会使过渡到 #5 变得微不足道。 但我想知道是否有其他方法或建议?
[1]https://www.polymer-project.org/3.0/docs/devguide/style-shadow-dom
[2]http://tabatkins.github.io/specs/css-apply-rule/
[3]https://meowni.ca/posts/part-theme-explainer/
[4] 一个简单的实现和一个使用它的例子:https://gist.github.com/mahhov/cbb27fcdde4ad45715d2df3b3ce7be40
实现:
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>
【问题讨论】:
-
只是想知道:跨浏览器功能对您来说有多重要?
-
好点,我忘了说,对于我的用例,我只关心最新版本的 chrome。
标签: javascript html css custom-element