您好,如果喜歡我的文章,可以關(guān)注我的公眾號(hào)「量子前端」,將不定期關(guān)注推送前端好文~
前言
由于最近作者在學(xué)習(xí)微前端,web component
也是其中一大特性,部分微前端框架使用到,也是深入學(xué)習(xí)了一下相關(guān)的知識(shí),分享出來。
Web Component是什么?
Web Component 實(shí)際上一系列技術(shù)的組合,主要包含 3 部分:
- 自定義元素。 在 HTML 基礎(chǔ)標(biāo)簽外擴(kuò)展自定義標(biāo)簽元素,也就是我們平時(shí)使用框架的"組件";
- Shadow DOM。 主要用于將 Shadow DOM 的內(nèi)容與外層 document DOM 隔離,可以理解為在document中的一個(gè)子容器,放置各種組件;
-
HTML 模板。 使用
<template>
來定義組件模板,使用<slot>
作為插槽使用(Vuer一定不陌生);
在一份html文件中的一個(gè)web component
看起來是這樣的:
<trace-ele name="webComponent" version="0.0.1" desc="原生態(tài)自帶隔離的組件">
<div slot="slot-ele">插槽內(nèi)容</div>
</trace-ele>
看起來很像Vue吧?接下來讓我們一個(gè)個(gè)demo學(xué)習(xí)web component
。
上手
由于Web Component
親和原生,因此無需其他包的依賴,一個(gè)index.html
和一個(gè)index.js
即可體驗(yàn)學(xué)習(xí)。
我們直接寫一個(gè)html模板,文章的案例組件統(tǒng)稱為<trace-ele />
index.html:
<body>
<template id="trace">
<div class="container">
<img
class="image"
src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
alt=""
/>
<p class="title">學(xué)習(xí)Web Component</p>
<p class="desc">Web Component是微前端沙盒隔離原理的重要知識(shí)</p>
<p class="price">¥25.00</p>
</div>
</template>
<trace-ele />
<script src="./index.js" />
</body>
這里我們寫了一個(gè)"模板"——template
,并在下面聲明了<trace-ele />
組件。
而實(shí)現(xiàn)這一切的原理在index.js
中。
class Trace extends HTMLElement {
constructor() {
super();
const templateEle = document.getElementById("trace");
const cloneEle = templateEle.content.cloneNode(true);
this.appendChild(cloneEle);
}
}
customElements.define("trace-ele", Trace);
Web Component
組件本質(zhì)是一個(gè)類繼承于HTMLElement
,當(dāng)customElements.define
聲明完組件后,類中的this
指向于組件本身,打印結(jié)果如下:
在初始化時(shí),需要提供給組件一個(gè)空殼,并且綁定template
元素的id,這樣就出現(xiàn)組件效果了。
看到這里是不是感覺和Vue
很像呢?接下來我們繼續(xù)升級(jí)組件的功能~
來點(diǎn)樣式吧
在上一節(jié)基礎(chǔ)上,給組件上點(diǎn)樣式,很簡(jiǎn)單,改變index.html
即可,在template
中加入style
:
<body>
<template id="trace">
<div class="container">
<img
class="image"
src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
alt=""
/>
<p class="title">學(xué)習(xí)Web Component</p>
<p class="desc">Web Component是微前端沙盒隔離原理的重要知識(shí)</p>
<p class="price">¥25.00</p>
</div>
<style>
.container {
display: inline-flex;
flex-direction: column;
border-radius: 6px;
border: 1px solid silver;
padding: 16px;
margin-right: 16px;
}
.image {
border-radius: 6px;
}
.title {
font-weight: 500;
font-size: 16px;
line-height: 22px;
color: #222;
margin-top: 14px;
margin-bottom: 9px;
}
.desc {
margin-bottom: 12px;
line-height: 1;
font-size: 14px;
}
.price {
font-size: 14px;
}
</style>
</template>
<trace-ele />
<script src="./index.js" />
</body>
樣式生效:
但是這里如果給一個(gè)通用標(biāo)簽的樣式,就像這樣:
<body>
<p>組件外的P標(biāo)簽</p>
<template>
<p>組件中的P標(biāo)簽</p>
<style>
p {
color: red;
}
...
.container {}
</style>
</template>
</body>
效果如下:
可以看到組件外的p標(biāo)簽
也被影響了,顏色變?yōu)榧t色,而在組件概念中這個(gè)樣式其實(shí)只期望作用于組件本身。這也是樣式隔離的概念,而很幸運(yùn),Web Component
提供了開箱即用的樣式隔離方案。
為了不讓 <template>
里的 <style>
CSS 和全局的 CSS 有沖突,我們可以將組件掛在到 Shadow Root 上,再用 Shadow Root 掛到外層的 document DOM 上,這樣就可以實(shí)現(xiàn) CSS 的隔離啦:
class Trace extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
const templateEle = document.getElementById("trace");
const cloneEle = templateEle.content.cloneNode(true);
this.shadowRoot.appendChild(cloneEle);
}
}
customElements.define("trace-ele", Trace);
從控制臺(tái)中觀察:
而如果有多個(gè)組件本質(zhì)其實(shí)就是在document
中有多個(gè)Shadow Root
。
整個(gè)DOM架構(gòu)圖是這樣的:
Shadow DOM 的一大優(yōu)點(diǎn)是能將 DOM 結(jié)構(gòu)、樣式、行為與 Document DOM 隔離開,非常適合做組件的封裝,因此它能成為 Web Component 的重要組成部分之一。
Props
與Vue
、React
一樣,Web Component
也提供了父?jìng)髯拥男问健?/p>
index.html:
<trace-ele name="webComponent" version="0.0.1" desc="原生態(tài)自帶隔離的組件">
這里傳了3個(gè)props給組件,在組件中打印this
如下:
火眼金睛的我已經(jīng)找到了在組件中接受傳參的入口:
做一個(gè)簡(jiǎn)單的動(dòng)態(tài)賦值:
class Trace extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
const templateEle = document.getElementById("trace");
const cloneEle = templateEle.content.cloneNode(true);
cloneEle.querySelector('.container > .title').textContent = this.getAttribute('name');
cloneEle.querySelector('.container > .price').textContent = this.getAttribute('version');
cloneEle.querySelector('.container > .desc').textContent = this.getAttribute('desc');
this.shadowRoot.appendChild(cloneEle);
}
}
customElements.define("trace-ele", Trace);
搞定~
Slot
HTML 模板的另一個(gè)好處是可以像 Vue
一樣使用 <slot>
。比如,現(xiàn)在我們可以在這個(gè) <trace-ele>
最下面添加一個(gè)插槽:
<body>
<template id="trace">
<div class="container">
<p>組件中的P標(biāo)簽</p>
<img
class="image"
src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
alt=""
/>
<p class="title">學(xué)習(xí)Web Component</p>
<p class="desc">Web Component是微前端沙盒隔離原理的重要知識(shí)</p>
<p class="price">¥25.00</p>
<slot name="slot-ele"></slot>
</div>
<style>
...
</style>
</template>
<trace-ele name="webComponent" version="0.0.1" desc="原生態(tài)自帶隔離的組件">
<div slot="slot-ele">插槽內(nèi)容</div>
</trace-ele>
</body>
這樣我們就可以實(shí)現(xiàn)自定義插槽內(nèi)容了。
事件綁定
Web Component
也可以給組件中元素或者插槽綁定事件。
class Trace extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
const templateEle = document.getElementById("trace");
const cloneEle = templateEle.content.cloneNode(true);
cloneEle
.querySelector(".container > .title")
.addEventListener("click", this.onClick);
this.shadowRoot.appendChild(cloneEle);
}
onClick = () => {
alert("Click Me!");
};
}
customElements.define("trace-ele", Trace);
總結(jié)
上面主要給大家分享了一下 Web Component 的一些使用方法??偟膩碚f,Web Component 是一系列 API 的組合:文章來源:http://www.zghlxwxcb.cn/news/detail-439156.html
- Custom Element:注冊(cè)和使用組件
- Shadow DOM:隔離 CSS
- HTML template 和 slot:靈活的 DOM 結(jié)構(gòu)
它看起來仿佛是現(xiàn)在主流框架的基建實(shí)現(xiàn),框架也正是基于原生的能力實(shí)現(xiàn)出一整套的解決方案,就比如Vue的響應(yīng)式以來追蹤、模板語法數(shù)據(jù)綁定,都是我們希望看到的。文章來源地址http://www.zghlxwxcb.cn/news/detail-439156.html
到了這里,關(guān)于一文讀懂Web Component的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!