我有一个自定义元素(没有shadow DOM),我希望能够在任何地方使用,甚至在另一个可能使用shadow DOM的自定义元素中。但是,我不确定如何在两个地方都能使用这些样式。
例如,假设我创建了一个简单的fancy-button
元素:
class fancyButton extends HTMLElement {
constructor() {
super();
this.innerHTML = `
<style>
fancy-button button {
padding: 10px 15px;
background: rgb(62,118,194);
color: white;
border: none;
border-radius: 4px
}
</style>
<button>Click Me</button>`;
}
}
customElements.define('fancy-button', fancyButton);
<fancy-button></fancy-button>
在shadow DOM元素中,插入的样式标记将允许fancy-button
样式工作。但是,如果在shadow DOM元素之外使用此组件,则每次使用该元素时都会复制样式标记。
如果我将样式标记作为html导入文件的一部分添加,那么样式只能在影子DOM之外工作,但至少它们只被声明一次。
<!-- fancy-button.html -->
<style>
fancy-button button {
padding: 10px 15px;
background: rgb(62,118,194);
color: white;
border: none;
border-radius: 4px
}
</style>
<script>
class fancyButton extends HTMLElement {
constructor() {
super();
this.innerHTML = `<button>Click Me</button>`;
}
}
customElements.define('fancy-button', fancyButton);
</script>
添加自定义元素样式以处理影子DOM内外使用的最佳方法是什么?
答案 0 :(得分:1)
您可能希望将这些样式放在一个单独的CSS文件中,并与您的元素JS一起销售。但正如您已经指出的那样,如果您将元素放在另一个元素的Shadow DOM中,那么这些样式将无法在该范围内工作。出于这个原因,通常最好只创建一个阴影根并在那里弹出你的样式。你之所以不想这么做的原因吗?
答案 1 :(得分:1)
所以我能够找到一个解决方案,感谢Supersharp关于检查我们是否在影子DOM中的建议。
首先,您将样式添加为导入文件的一部分,以便默认情况下样式应用于shadow DOM之外。然后,当元素添加到DOM时,我们检查getRootNode()
以查看它是否已添加到ShadowRoot
节点。如果有,并且样式尚未注入根目录,那么我们可以手动注入样式。
var div = document.createElement('div');
var shadow = div.attachShadow({mode: 'open'});
shadow.innerHTML = '<fancy-button></fancy-button>';
document.body.appendChild(div);
<style data-fs-dialog>
fancy-button button {
padding: 10px 15px;
background: rgb(62,118,194);
color: white;
border: none;
border-radius: 4px
}
</style>
<script>
class fancyButton extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.innerHTML = `<button>Click Me</button>`;
var root = this.getRootNode();
// In polyfilled browsers there is no shadow DOM so global styles still style
// the "fake" shadow DOM. We need to test for truly native support so we know
// when to inject styles into the shadow dom. The best way I've found to do that
// is to test the toString output of a shadowroot since `instanceof ShadowRoot`
// returns true when it's just a document-fragment in polyfilled browsers
if (root.toString() === '[object ShadowRoot]' && !root.querySelector('style[data-fs-dialog]')) {
var styles = document.querySelector('style[data-fs-dialog]').cloneNode(true);
root.appendChild(styles);
}
}
}
customElements.define('fancy-button', fancyButton);
</script>
<fancy-button></fancy-button>
当所有浏览器都支持shadow DOM中的<link rel=stylesheet>
时,内联脚本可以像robdodson建议的那样变成外部样式表,并且代码更清晰。