在 Web Component 中有些特别的 css styling 可以设定 ,
ex : 如果我们想要设定元件根元素 (Root Element) 的底色时 , 可以使用 :host 来做设定
如果我们想要根据外部的 dom 设定 根元素的底色时 , 可以使用 :host-context(.dark-wrap) 来做设定
shadow-dom 提供将样式内外隔离的方式 , 但是当我们真的需要设定一些内外都要有的样式时 ,
我们可以用 my-tab::part(tab-head) 来做设定 , 它会穿过 shadow-dom 将我们想设定的样式给设定上去
如果想要指定 slot 的底色 , 举例想要设定 day-08 的 modal-body 它的底色 , 可以用 ::slotted(*) 来做设定
以下整理跟 Web Component 相关的 styling 有哪些
pseudo-classes | 说明 |
---|---|
:defined | 所有使用 CustomElementRegistry.define() 的 Tag 内容都设定的样式 |
:host | 设定元件的根样式 |
:host(.bg-red) | 根据原件上的属性 , 设定不同的根样式 |
:host-context(.dark-wrap) | 根据原件外层的情况 , 设定不同的根样式 |
::part | 设定可以穿过 shadow-dom 的样式 |
::slotted(*) | 设定所有 slot 都共用的样式 |
下面我们就使用常用的 Tab 页签 , 来学习 Web Component 中有哪些特别的 css 设定吧 !
下面我们用一些范例来说明上面表列的那些样式设定吧 !
:host 相关设定的解说
<div class="dark-wrap">
<x-foo class="foo">
<"shadow tree">
<link rel="stylesheet" href="./inner.css">
<div class="foo">...</div>
</>
</x-foo>
</div>
在 inner.css 中设定以下内容 , 将会设定对应的样式
::slotted() 相关设定的解说
<link rel="stylesheet" href="./outer.css">
<x-foo>
<div id="one" slot="foo" class="foo">...</div>
<div id="two" slot="foo">...</div>
<div id="three" class="foo">
<div id="four" slot="foo">...</div>
</div>
<"shadow tree">
<div id="five" part="bar">...</div>
<div id="six">...</div>
<slot name="foo"></slot>
</"shadow tree">
</x-foo>
在 outer.css 中设定以下内容 , 将会设定对应的样式
建立 tab.css
*, *::before, *::after {
box-sizing: border-box;
}
.tab-head {
color: #000;
background-color: #f1f1f1;
border-bottom: 1px solid #ccc;
display: flex;
}
.tab-head .item {
cursor: pointer;
font-size: 20px;
padding: 8px 16px;
height: 100%;
display: flex;
align-items: center;
}
.tab-head .item:hover {
background-color: #ccc;
}
.tab-head .item.active {
color: #fff;
background-color: #616161;
}
/* 所有使用 CustomElementRegistry.define() 的 Tag 都上色 */
:defined {
border-left: 2px solid rebeccapurple;
}
/* component 的根 styling */
:host {
width: 1000px;
border: 1px solid #ccc;
box-shadow: 8px 8px 10px 2px rgba(0,0,0,0.5);
}
/* 根据 tag 上的属性来设定 :host 的样式 */
:host(.bg-light-green) {
background-color: #66ff16;
}
/* 根据外部的 dom 来设定 :host 的样式 */
:host-context(.thin) {
width: 700px;
box-shadow: none;
}
/* Selects any <span> placed inside a slot */
::slotted(div) {
font-weight: 900;
padding: 8px 24px;
background-color: #ffffff;
animation: fadeIn 0.5s ease-in-out;
}
建立 tab.js
// tab.js
class MyTab extends HTMLElement {
connectedCallback() {
const tabHeaders = [...this.querySelectorAll('.item')]
const tabBodies = [...this.querySelectorAll('[slot]')]
const tabBodyStr = tabBodies
.map(tabContent => `<slot name="${tabContent.getAttribute('slot')}" class="city tab-body"></slot>`)
.join('')
const styleStr = `<link rel="stylesheet" href="./tab.css">`
const htmlStr = `
<div class="tab-head" part="tab-head">
${tabHeaders.map(head => head.outerHTML).join('')}
</div>
${tabBodyStr}
`
this.attachShadow({mode: 'open'}).innerHTML = styleStr + htmlStr;
const items = this.shadowRoot.querySelectorAll('.item');
[...items].map(item => item.addEventListener('click', e => this._tabClick(e)))
}
_tabClick(e) {
const tabName = e.target.innerText;
const shadowRoot = this.shadowRoot;
const tabBodies = this.querySelectorAll(".tab-body");
const items = shadowRoot.querySelectorAll(".tab-head .item");
tabBodies.forEach(content => (content.slot === tabName) ? content.style.display = "block" : content.style.display = "none")
items.forEach(item => (item.innerText === tabName) ? item.classList.add('active') : item.classList.remove('active'))
}
}
window.customElements.define('my-tab', MyTab);
在 show-wc.html 中引用
// show-wc.html
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<title>显示自订的 WC 元件</title>
<style>
body {
display: flex;
gap: 40px;
margin: 50px;
flex-wrap: wrap;
background-color: #ebf5fc;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* 利用 part 属性 , 可以穿过 shadow-dom 做设定 */
my-tab::part(tab-head) {
color: rgba(254, 8, 8, 0.93);
font-weight: 900;
}
my-tab::part(tab-head):hover {
transform: skewX(-20deg) translateX(8px);
}
</style>
</head>
<body>
<my-tab class="bg-light-green">
<div class="item">London</div>
<div class="item">Paris</div>
<div class="item">Tokyo</div>
<div slot="London" class="tab-body" id="tabs">
<h2>London</h2>
<p>London is the capital of England.</p>
</div>
<div slot="Paris" class="tab-body" style="display:none">
<h2>Paris</h2>
<p>Paris is the capital of France.</p>
</div>
<div slot="Tokyo" class="tab-body" style="display:none">
<h2>Tokyo</h2>
<p>Tokyo is the capital of Japan.</p>
</div>
</my-tab>
<div class="thin">
<my-tab>
<div class="item">London</div>
<div class="item">Paris</div>
<div class="item">Tokyo</div>
<div slot="London" class="tab-body" id="tabs">
<h2>London</h2>
<p>London is the capital of England.</p>
</div>
<div slot="Paris" class="tab-body" style="display:none">
<h2>Paris</h2>
<p>Paris is the capital of France.</p>
</div>
<div slot="Tokyo" class="tab-body" style="display:none">
<h2>Tokyo</h2>
<p>Tokyo is the capital of Japan.</p>
</div>
</my-tab>
</div>
<script src="./tab.js"></script>
</body>
</html>
完成 !!
如果想直接体验成果 , 请到 web-component-pseudo-classes.html 查看
<<: 方法论(Know how):隐藏在程序书背後的系统逻辑与资讯汇整方法
通常关联都是两两张资料表之间的关系,而多型态关联则是打破这个限制让一张表可以同时关连到两张以上的资料...
Data format CSV(Comma-Separated Values)可以说是在偏乡环境最...
前言 今天要来讲 this.props 了, 但在那之前我发现我还没讲过 this XD 就跟学英文...
今天跟朋友在讨论《过度努力》时,朋友说自己对「冒牌者效应」这个词的感觉很复杂 他觉得自己的确有这个词...
混入 Mixins 当我们在编写 css 时,常常会发现有要重复套用的地方,像是一个网站的主题样式,...