当前位置:网站首页>[web technology] 1233 seconds understand web component
[web technology] 1233 seconds understand web component
2022-07-02 17:22:00 【pingan8787】
What is it?
Web Components In fact, a combination of a series of technologies , It mainly includes 3 part :
Custom elements . stay HTML Extend custom label elements beyond the basic label
Shadow DOM. Mainly used to Shadow DOM Content and outer layer of document DOM Isolation
HTML Templates . Use
<template>
To define component templates , Use<slot>
Use as a slot
It is precisely because it is a series of API The combination of , So in use , We need to focus on these at the same time API The compatibility of :



After using the above technology reasonably , Can Will function 、 Custom logic is encapsulated in the tag , Improve development efficiency by reusing these custom components . It sounds like Vue.js
and React
The one you made , actually , In the use of Web Components When , It's also very similar .
Get started
Next, we implement a <book-card>
Web Component Let's learn how to use it .

Custom elements
First , Create a index.html
, Call directly inside <book-card>
Components .
<body>
<book-card></book-card>
<script src="./BookCard.js"></script>
</body>
Because browsers don't know <book-card>
therefore , We need to be in BookCard.js
Register it in , And in index.html
Introduce and execute BookCard.js
.
class BookCard extends HTMLElement {
constructor() {
super();
const container = document.createElement('div')
container.className = 'container'
const image = document.createElement('img')
image.className = 'image'
image.src = "https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
const title = document.createElement('p')
title.className = 'title'
title.textContent = ' The sacrifice of Chernobyl '
const desc = document.createElement('p')
desc.className = 'desc'
desc.textContent = 'S·A· Alexeyevich '
const price = document.createElement('p')
price.className = 'price'
price.textContent = `¥25.00`
container.append(image, title, desc, price)
this.appendChild(container)
}
}
customElements.define('book-card', BookCard)
The above has realized the most basic DOM It's structured :

The above has been executing
createElement
And set whether the behavior of the attribute value is a bit like React OfReact.createElement
Well ?
HTML Templates
This generates... Line by line DOM The structure is not only tired of writing , It is also difficult for readers to understand at once . To solve this problem , We can use HTML Templates . Directly in HTML There's a <template>
Templates :
<body>
<template id="book-card-template">
<div class="container">
<img class="image" src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp" alt="">
<p class="title"> The sacrifice of Chernobyl </p>
<p class="desc">S·A· Alexeyevich </p>
<p class="price">¥25.00</p>
</div>
</template>
<book-card></book-card>
<script src="BookCard.js"></script>
</body>
Then call this template directly in the registration component :
class BookCard extends HTMLElement {
constructor() {
super();
const templateElem = document.getElementById('book-card-template')
const clonedElem = templateElem.content.cloneNode(true)
this.appendChild(clonedElem)
}
}
customElements.define('book-card', BookCard)
In this way
<template>
Is the writing style a little like what we are familiar withVue
It's framed ?
Writing style
done DOM after , Then we can write the style , Directly in <template>
Add a new one to it <style>
Elements , Then start writing CSS:
<body>
<template id="book-card-template">
<style>
p { margin: 0 }
.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; color: #8590a6; font-size: 14px; }
.price { color: #8590a6; font-size: 14px; }
</style>
<div class="container">
<img class="image" src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp" alt="">
<p class="title"> The sacrifice of Chernobyl </p>
<p class="desc">S·A· Alexeyevich </p>
<p class="price">¥25.00</p>
</div>
</template>
<book-card></book-card>
<script src="BookCard.js"></script>
</body>
I believe everyone will write like this CSS, So in order to reduce the length, we put CSS It's folded , The final effect is as follows :

Shadow DOM
In order not to let <template>
Inside <style>
CSS And the overall situation CSS There are conflicts , We can hang the components to Shadow Root On , Reuse Shadow Root Hanging on the outer layer document DOM On , In this way... Can be achieved CSS Isolation of :
class BookCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' })
const templateElem = document.getElementById('book-card-template')
const clonedElem = templateElem.content.cloneNode(true)
this.shadowRoot.appendChild(clonedElem)
}
}
customElements.define('book-card', BookCard)
Open console , You can see <template>
Of DOM All hung up on Shadow Root Yes :

Whole DOM The architecture is roughly like this :

Shadow DOM One of the great advantages of is the ability to DOM structure 、 style 、 Behavior and Document DOM To separate from each other , It is very suitable for packaging components , So it can be Web Component An important part of .
Shadow DOM It often appears in our daily development , such as <video>
In the element controls
Control DOM The structure is also hung on Shadow Root Under the :

Props
and Vue
and React
The components are the same , We can also do that Web Component Pass attributes on :
<body>
<template id="book-card-template">
<style>
...
</style>
<div class="container">
<img class="image" src="" alt="">
<p class="title"></p>
<p class="desc"></p>
<p class="price"></p>
</div>
</template>
<book-card
data-image="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
data-title=" The sacrifice of Chernobyl "
data-desc="S·A· Alexeyevich "
data-price="25.00"
></book-card>
<script src="BookCard.js"></script>
</body>
Then update these properties to DOM On :
const prefix = 'data-'
class BookCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' })
const templateElem = document.getElementById('book-card-template')
const clonedElem = templateElem.content.cloneNode(true)
clonedElem.querySelector('.container > .image').src = this.getAttribute(`${prefix}image`)
clonedElem.querySelector('.container > .title').textContent = this.getAttribute(`${prefix}title`)
clonedElem.querySelector('.container > .desc').textContent = this.getAttribute(`${prefix}desc`)
clonedElem.querySelector('.container > .price').textContent = `¥${this.getAttribute(`${prefix}price`)}`
this.shadowRoot.appendChild(clonedElem)
}
}
customElements.define('book-card', BookCard)
Generally speaking , For custom properties , We are used to using data-xxx
Named after the .
If you can think further , You can get these directly
attributes
, Then use it to do Proxy agent 、 Responsive assignment and other operations . Um. , Yes Vue It's too delicious !
const prefix = 'data-'
const attrList = Array.from(this.attributes);
const props = attrList.filter(attr => attr.name.startsWith(prefix))
// monitor props
watch(props)
Slot
HTML Another advantage of templates is that they can be like Vue
The use of <slot>
. such as , Now we can be here <book-card>
Add a... At the bottom action slot :
<template id="book-card-template">
<style>
...
</style>
<div class="container">
<img class="image" src="" alt="">
<p class="title"></p>
<p class="desc"></p>
<p class="price"></p>
<div class="action">
<slot name="action-btn"></slot>
</div>
</div>
</template>
When others want to use <book-card>
When the component , You can use them through slots and inject their customized content :
<book-card
data-image="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
data-title=" The sacrifice of Chernobyl "
data-desc="S·A· Alexeyevich "
data-price="25.00"
>
<button slot="action-btn" class="btn primary"> Buy </button>
</book-card>
<book-card
data-image="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
data-title=" The sacrifice of Chernobyl "
data-desc="S·A· Alexeyevich "
data-price="25.00"
>
<button slot="action-btn" class="btn danger"> Delete </button>
</book-card>

Interaction
We can still be like React Bind events to elements like that , For example, here for this action <slot>
Add click event :
class BookCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' })
const templateElem = document.getElementById('book-card-template')
const clonedElem = templateElem.content.cloneNode(true)
...
clonedElem.querySelector('.container > .action').addEventListener('click', this.onAction)
this.shadowRoot.appendChild(clonedElem)
}
onAction = () => {
alert('Hello World')
}
}

Be careful : there onAction
Is the arrow function , Because you need to bind this
, Point it to this BookCard
Components .
UI library
Maybe some students have begun to think : Since this thing can be used to encapsulate components , There is a corresponding Web Component UI The library? ? The answer is yes .
At present, there are some famous products produced by Microsoft FAST[2]:

Yes Google Produced Lit[3]:

And Tencent of our factory OMI[4]:

summary
The above mainly shares with you Web Component Some usage methods . in general ,Web Component Is a series of API The combination of :
Custom Element: Register and use components
Shadow DOM: Isolation CSS
HTML template and slot: agile DOM structure
About Web Component The content of , It's almost finished , I don't know how you feel after reading . It gives me the feeling that it provides the function of native component encapsulation , But there are a lot of things not done , For example, what we want to see :
image Vue That kind of responsive tracking of data
image Vue That kind of template syntax 、 Data binding
image React Like that DOM Diff
image React Like that
React.createElement
Of JSX How to write it...
These are what we hope “ Frame features ” Web Component Are not provided . This is because Web Component All the contents are made by API form , And these API As a specification, keep the function single 、 The principle of orthogonality , Instead of acting like Vue
, React
Such componentization “ frame ”. I know that, too 《Web Component And the class React、Angular、Vue Who will become the future of component technology ?》[5] The answer said :
The responsibility of the framework is to provide a complete set of solutions , And the platform API The design requirement of is never to provide a complete set of solutions ( That is to ensure zero coupling 、 orthogonal ), This is the fundamental contradiction that cannot be reconciled .
Web Component The main benefit is native support 、 No external dependence . One index.html
+ main.js
You can complete the component registration and use .
at present , It's still developing , It can also be used in production environments , image single-spa Layout Engine as well as MicroApp It's an example , Another scenario is that you can TextArea
, Video
Such functional components are used in Web Component To encapsulate .
Reference material
[1]
Project code : https://github.com/haixiangyan/bookcard-web-component
[2]FAST: https://www.fast.design/
[3]Lit: https://lit.dev/
[4]OMI: https://tencent.github.io/omi/
[5]《Web Component And the class React、Angular、Vue Who will become the future of component technology ?》: https://www.zhihu.com/question/58731753/answer/158331367
1. JavaScript Revisit the series (22 Complete )
2. ECMAScript Revisit the series (10 Complete )
3. JavaScript Design patterns Revisit the series (9 Complete )
4. Regular / frame / Algorithm etc. Revisit the series (16 Complete )
5. Webpack4 introduction ( On )|| Webpack4 introduction ( Next )
6. MobX introduction ( On ) || MobX introduction ( Next )
7. 120+ Summary of original series
reply “ Add group ” Communicate and learn with the big guys ~
Click on “ Read the original ” see 130+ Original articles
边栏推荐
- QStyle实现自绘界面项目实战(二)
- 【Leetcode】14. 最长公共前缀
- 云通信接口更新迭代——SUBMAIL API V4正式上线
- VScode知识点——常见报错
- 871. Minimum refueling times
- executescalar mysql_ ExecuteScalar()
- visibilitychange – 指定标签页可见时,刷新页面数据
- 2020 "Lenovo Cup" National College programming online Invitational Competition and the third Shanghai University of technology programming competition (a sign in, B sign in, C sign in, D thinking +mst
- Blog theme "text" summer fresh Special Edition
- Visibilitychange – refresh the page data when the specified tab is visible
猜你喜欢
福元医药上交所上市:市值105亿 胡柏藩身价超40亿
AP and F107 data sources and processing
深度之眼(二)——矩阵及其基本运算
【征文活动】亲爱的开发者,RT-Thread社区喊你投稿啦
Exploration of mobile application performance tools
[essay solicitation activity] Dear developer, RT thread community calls you to contribute
超卓航科上市:募资9亿市值超60亿 成襄阳首家科创板企业
Ap和F107数据来源及处理
如何与博格华纳BorgWarner通过EDI传输业务数据?
2020 "Lenovo Cup" National College programming online Invitational Competition and the third Shanghai University of technology programming competition (a sign in, B sign in, C sign in, D thinking +mst
随机推荐
ThreadLocal
云通信接口更新迭代——SUBMAIL API V4正式上线
ROS知识点——ros::NodeHandle n 和 nh(“~“)的区别
Un an à dix ans
PCL知识点——体素化网格方法对点云进行下采样
Qstype implementation of self drawing interface project practice (II)
Geoserver: publishing PostGIS data sources
Understand one article: four types of data index system
LeetCode:1380. Lucky number in matrix -- simple
宝宝巴士创业板IPO被终止:曾拟募资18亿 唐光宇控制47%股权
福元医药上交所上市:市值105亿 胡柏藩身价超40亿
七张图,学会做有价值的经营分析
人生的开始
How to quickly distinguish controlled components from uncontrolled components?
2022 interview questions
博客主题 “Text“ 夏日清新特别版
相信自己,这次一把搞定JVM面试
Sword finger offer 26 Substructure of tree
深度之眼(二)——矩阵及其基本运算
Eth data set download and related problems