foreword
Since the author is learning about micro-frontends recently, web component
which is also one of the major features, some micro-frontend frameworks are used, and I have studied relevant knowledge in depth and shared it.
What are Web Components?
Web Component is actually a combination of a series of technologies, mainly including 3 parts:
- Custom elements. Extend the custom label element outside the basic HTML label, which is the "component" of the framework we usually use;
- Shadow DOM. It is mainly used to isolate the content of Shadow DOM from the outer document DOM, which can be understood as a sub-container in the document to place various components;
- HTML templates. Use
<template>
to define component templates,<slot>
use as slots (Vuer must be no stranger);
One in an html file web component
looks like this:
<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">
<div slot="slot-ele">插槽内容</div>
</trace-ele>
Looks a lot like Vue, right? Next, let's learn demos one by one web component
.
good
Due to Web Component
the native affinity, there is no need to rely on other packages, index.html
and index.js
you can experience learning one by one.
We directly write an html template, and the case components of the article are collectively called<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">学习Web Component</p>
<p class="desc">Web Component是微前端沙盒隔离原理的重要知识</p>
<p class="price">¥25.00</p>
</div>
</template>
<trace-ele />
<script src="./index.js" />
</body>
Here we write a "template" - template
and declare <trace-ele />
the components below.
And the principle of realizing all this is in index.js
the.
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
The essence of a component is that a class inherits from it HTMLElement
. After customElements.define
the component is declared, the pointer in the class this
points to the component itself. The printed results are as follows:
When initializing, you need to provide the component with an empty shell, and bind template
the id of the element, so that the component effect appears.
Does it feel Vue
similar to seeing here? Next, let's continue to upgrade the functions of the components~
let's style
On the basis of the previous section, it is very simple to add a style to the component, index.html
just change it, and template
add 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">学习Web Component</p>
<p class="desc">Web Component是微前端沙盒隔离原理的重要知识</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>
The styles take effect:
But here if you give a general label style, like this:
<body>
<p>组件外的P标签</p>
<template>
<p>组件中的P标签</p>
<style>
p {
color: red;
}
...
.container {
}
</style>
</template>
</body>
The effect is as follows:
It can be seen that the outside of the component p标签
is also affected, and the color changes to red, but in the component concept, this style is actually only expected to act on the component itself. This is also the concept of style isolation, and fortunately, Web Component
an out-of-the-box style isolation solution is provided.
In order to prevent conflicts <template>
between the internal <style>
CSS and the global CSS, we can hang the component on the Shadow Root, and then use the Shadow Root to hang it on the outer document DOM, so that CSS isolation can be achieved:
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);
Observe from the console:
And if there are multiple components, the essence is that document
there are multiple in Shadow Root
.
The entire DOM architecture diagram is as follows:
One of the advantages of Shadow DOM is that it can isolate DOM structure, style, and behavior from Document DOM. It is very suitable for component encapsulation, so it can become one of the important components of Web Component.
Props
Vue
Same as and React
, Web Component
it also provides the form of father-to-son.
index.html:
<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">
Here 3 props are passed to the component, and printed in the component this
as follows:
With keen eyes, I have found the entrance to accept parameter passing in components:
Do a simple dynamic assignment:
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);
done~
Slot
Another benefit of HTML templates is that they can Vue
be used like <slot>
. For example, now we can <trace-ele>
add a slot at the bottom of this:
<body>
<template id="trace">
<div class="container">
<p>组件中的P标签</p>
<img
class="image"
src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
alt=""
/>
<p class="title">学习Web Component</p>
<p class="desc">Web Component是微前端沙盒隔离原理的重要知识</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="原生态自带隔离的组件">
<div slot="slot-ele">插槽内容</div>
</trace-ele>
</body>
This way we can implement custom slot content.
event binding
Web Component
You can also bind events to elements or slots in components.
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);
Summarize
The above mainly shared with you some usage methods of Web Component. In general, Web Component is a combination of a series of APIs:
- Custom Element : Register and use components
- Shadow DOM : Isolate CSS
- HTML template and slot : flexible DOM structure
It seems to be the infrastructure implementation of the current mainstream framework, and the framework is also based on the native capabilities to implement a complete set of solutions, such as Vue's responsive tracking and template syntax data binding, all of which we want to see .