是否有任何方法可以处理CSS如何应用于web组件,就像使用attributeChangedCallback处理属性一样。
我正在开发几个web组件,这些组件将从使用CSS类进行样式设计中受益,但我需要更改多种样式才能使其看起来正确(例如,如果设置控件的颜色,用户会期望一个元素的边框颜色和另一个元素在shadow DOM中的字体颜色发生变化(。
在下面的简单web组件示例中,有什么方法可以让.usingCSS { color: red; }
更改切换开关的颜色吗?
// based on https://www.w3schools.com/howto/howto_css_switch.asp
class W3schoolsToggleSwitch extends HTMLElement {
constructor() {
super();
var shadow = this.attachShadow({ mode: "open" });
this.span = document.createElement("span");
this.span.innerHTML = `
<style>
/* The switch - the box around the slider */
.switch {
--color: #2196F3;
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: var(--color);
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
</style>
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
`;
shadow.appendChild(this.span);
}
static get observedAttributes() {
return ["color"];
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(name, newValue);
if ("color" === name) {
this.shadowRoot
.querySelector(".switch")
.style.setProperty("--color", newValue);
}
}
get color() {
return this.getAttribute("color");
}
set color(value) {
return this.setAttribute("color", value);
}
}
customElements.define("w3schools-toggle-switch", W3schoolsToggleSwitch);
.usingCSS {
color: red;
}
default:
<w3schools-toggle-switch></w3schools-toggle-switch>
<br><br> color attribute used to change the color to green:
<w3schools-toggle-switch color="green"></w3schools-toggle-switch>
<br><br> can you change the color with CSS?:
<w3schools-toggle-switch class="usingCSS"></w3schools-toggle-switch>
从外部与<
链接>
您可以将CSS样式应用于调整ShadowDOM中<link>
元素的Web组件。
#shadow-root
<link rel="stylesheet" href="default.css">
attributeChangedCallback( name, old, value ) {
if (name === 'class')
this.shadowRoot.querySelector( 'link' ).href = value + ".css"
}
在Shadow DOM:host((伪类函数中定义样式
可以根据上下文应用不同的样式。可以组合多个类。
customElements.define( 'custom-element', class extends HTMLElement {
constructor() {
super()
this.attachShadow( { mode: 'open' } )
.innerHTML = `
<style>
:host( .red ) { color: red }
:host( .blue ) { color: blue }
:host( .border ) { border: 1px solid }
</style>
Hello`
}
} )
ce1.onclick = ev => ev.target.classList.add( 'border' )
<custom-element class="red" id="ce1"></custom-element>
<custom-element class="blue border"></custom-element>
在Chrome/Opera上:使用可构建的样式表
创建一个(或多个(样式表并将其应用于Shadow DOM。您可以将多个样式表应用于同一个Shadow DOM。
var ss = []
ss['red'] = new CSSStyleSheet
ss.red.replaceSync( 'span { color: red }' )
ss['green'] = new CSSStyleSheet
ss.green.replaceSync( 'span { color: green }' )
ss['border'] = new CSSStyleSheet
ss.border.replaceSync( 'span { border: 1px solid }' )
customElements.define( 'custom-element', class extends HTMLElement {
constructor() {
super()
this.attachShadow( { mode: 'open' } )
.innerHTML = `<span>Hello</span>`
}
static get observedAttributes() { return [ 'class' ] }
attributeChangedCallback() {
this.shadowRoot.adoptedStyleSheets = [ ...this.classList ].map( cl => ss[ cl ] )
}
} )
ce1.onclick = ev => ev.target.classList.add( 'border' )
<custom-element class="red" id="ce1"></custom-element>
<custom-element class="green border"></custom-element>
在Supersharps答案上扩展。
当你还不能使用可构建样式表时:
您可以(粗暴地(从Host文档导入整个STYLE定义。
onload=this.disabled=true
以防止对文档DOM 设置样式
或者创建承载(并服务(STYLE
元件的<my-themes></my-themes>
组件
customElements.define( 'custom-element', class extends HTMLElement {
constructor() {
super()
this.root=this.attachShadow( { mode: 'open' } );
this.root.innerHTML = `<style>div{font-size:40px}</style>`
+`<style id="theme"></style><div>Click Me</div>`;
let themes = window.themes;//duplicate IDs create a global NodeList
let themeNr = 0;
this.root.addEventListener('click', ev =>
this.theme = themes[ themeNr<themes.length ? themeNr++ : themeNr=0 ].innerHTML);
}
set theme(css){
this.root.getElementById('theme').innerHTML = css;
}
} )
<style id="themes" onload="this.disabled=true">
div{
background:yellow;
}
</style>
<style id="themes" onload="this.disabled=true">
div{
background:hotpink;
font-size:30px;
}
</style>
<style id="themes" onload="this.disabled=true">
div{
background:red;
color:white;
}
div::after{
content:" theme2"
}
</style>
<custom-element></custom-element>
<custom-element></custom-element>
<custom-element></custom-element>
<div>Main Document</div>