Ste*_*ert 5 html web-component shadow-dom custom-element
我有一个自定义元素(没有 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);
Run Code Online (Sandbox Code Playgroud)
<fancy-button></fancy-button>
Run Code Online (Sandbox Code Playgroud)
在 shadow DOM 元素内,插入的样式标签将允许fancy-button
样式工作。但是,如果在 shadow DOM 元素之外使用此组件,则每次使用该元素时都会复制样式标记。
相反,如果我将样式标记添加为 html 导入文件的一部分,那么样式只能在 shadow 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>
Run Code Online (Sandbox Code Playgroud)
添加处理 shadow DOM 内部和外部使用的自定义元素样式的最佳方法是什么?
因此,由于 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);
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)
当所有浏览器都支持<link rel=stylesheet>
Shadow DOM 时,内联脚本就可以按照 robdodson 的建议变成外部样式表,并且代码会更干净一些。