开发中,还是会遇到须要引入内部 CSS 到 Shadow DOM 状况,那么如何解决呢?作者就最近遇到的状况给出如下几种计划。
一、@import
示例代码
const template = document.createElement('template');
class WhatsUp extends HTMLElement {connectedCallback() {const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innderHTML = `
<style>
@import "./index.css"; // 外围代码
</style>
<div>Sup</div>
`
}
}
window.customElements.define('whats-up', WhatsUp);
长处:此办法兼容性十分好,点击查看 caniuse。
毛病:性能
二、::part
::part
CSS 伪元素示意在暗影树中任何匹配 part
属性的元素。
示例代码
HTML
<template id="whats-up">
<div part="sup">Sup</div>
<div part="foo">Sup</div>
</template>
<whats-up></whats-up>
CSS
whats-up::part(sup) {/* 款式作用于 `sup` 局部 */}
whats-up::part(foo) {/* 款式作用于 `foo` 局部 */}
长处:简洁明了
毛病:兼容性不太好,点击查看 caniuse。
三、var
CSS 自定义属性能够穿透到 Shadow DOM 中!
示例代码
JS
const template = document.createElement('template');
template.innerHTML = `
<style>
button {background: var(--background);
color: var(--color);
padding: var(--padding);
font-size: var(--font-size);
border: 0;
}
</style>
<div>Sup</div>`;
CSS
whats-up {
--background: #1E88E5;
--color: white;
--padding: 2rem 4rem;
--font-size: 1.5rem;
}
长处:兼容性好
毛病:比拟局限,只能内部定几个,款式不能“自在翱翔”
四、通过属性传入
示例代码
JS
class Whatsup extends HTMLElement {static get observedAttributes() {return ['css']}
constructor() {super();
}
get css() {return this.getAttribute('css');
}
set css(value) {if (value === null || value === false) {this.removeAttribute('css');
} else {this.setAttribute('css', value);
}
}
connectedCallback() {
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<style>
:host{display: flex;}
${this.css} // 外围代码
</style>
<div class="name">Sup</div>
`;
}
}
HTML
<whats-up
css="
.name{color: red;}
"
></whats-up>
长处:款式能够随便批改
毛病:代码不够优雅
五、自定义组件外部定义批改款式函数
示例代码
JS
class Whatsup extends HTMLElement {
// ...
// 外围代码
reStyle(els, styles) {const elements = Array.isArray(els) ? els : [els];
elements.forEach((element) => Object.assign(element.style, styles));
}
}
HTML
<whats-up></whats-up>
<script>
const myEle = document.querySelector('whats-up')
const title = myEle.shadowRoot.querySelector('.title');
myEle.reStyle(title, {
color: 'red',
width: '200px',
})
</script>
六、通过 slot 内部设置款式
示例代码
JS
class WhatsUp extends HTMLElement {constructor() {super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<div>
<slot name="header"></slot>
</div>
`;
}
}
customElements.define('whats-up', WhatsUp);
HTML
<style>
.header{color: red;}
</style>
<whats-up>
<div slot="header" class="header">
what's up
</div>
</whats-up>
七、fetch 获取
示例代码
class WhatsUp extends HTMLElement {constructor() {super();
const shadowRoot = this.attachShadow({mode: 'open'});
// 获取款式
fetch('./index.css').then(res => res.text()).then(data => {let node = document.createElement('style');
node.innerHTML = data;
this.shadowRoot.appendChild(node);
});
// ...
}
}
customElements.define('whats-up', WhatsUp);
长处:长处是兼容性不错,反对 Shadow DOM 的元素均反对此语法;以及性能还 OK
毛病:不优雅
八、CSS module import
此办法应用浏览器原生的 import 语法,然而 import 的是 CSS 文件而不是 JS 文件。
也就是把 CSS 文件间接作为模块引入。
示例代码
import styles from "index.css";
class WhatsUp extends HTMLElement {constructor() {
// ...
// 外围代码
shadow.adoptedStyleSheets = [styles];
}
}
长处:长处是应用方便快捷且是官网举荐办法,或者是 import CSS 模块就是为了这个场景才反对的;以及性能 OK,import 自身就是异步过程。
毛病:兼容性不佳,狠狠戳这里 caniuse。
总结
各种办法实用场景各不相同,小心食用。