赞
踩
您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~
由于最近作者在学习微前端,web component
也是其中一大特性,部分微前端框架使用到,也是深入学习了一下相关的知识,分享出来。
Web Component 实际上一系列技术的组合,主要包含 3 部分:
<template>
来定义组件模板,使用 <slot>
作为插槽使用(Vuer一定不陌生);在一份html文件中的一个web component
看起来是这样的:
<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">
<div slot="slot-ele">插槽内容</div>
</trace-ele>
看起来很像Vue吧?接下来让我们一个个demo学习web component
。
由于Web Component
亲和原生,因此无需其他包的依赖,一个index.html
和一个index.js
即可体验学习。
我们直接写一个html模板,文章的案例组件统称为<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>
这里我们写了一个"模板"——template
,并在下面声明了<trace-ele />
组件。
而实现这一切的原理在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
组件本质是一个类继承于HTMLElement
,当customElements.define
声明完组件后,类中的this
指向于组件本身,打印结果如下:
在初始化时,需要提供给组件一个空壳,并且绑定template
元素的id,这样就出现组件效果了。
看到这里是不是感觉和Vue
很像呢?接下来我们继续升级组件的功能~
在上一节基础上,给组件上点样式,很简单,改变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">学习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>
样式生效:
但是这里如果给一个通用标签的样式,就像这样:
<body>
<p>组件外的P标签</p>
<template>
<p>组件中的P标签</p>
<style>
p {
color: red;
}
...
.container {}
</style>
</template>
</body>
效果如下:
可以看到组件外的p标签
也被影响了,颜色变为红色,而在组件概念中这个样式其实只期望作用于组件本身。这也是样式隔离的概念,而很幸运,Web Component
提供了开箱即用的样式隔离方案。
为了不让 <template>
里的 <style>
CSS 和全局的 CSS 有冲突,我们可以将组件挂在到 Shadow Root 上,再用 Shadow Root 挂到外层的 document DOM 上,这样就可以实现 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);
从控制台中观察:
而如果有多个组件本质其实就是在document
中有多个Shadow Root
。
整个DOM架构图是这样的:
Shadow DOM 的一大优点是能将 DOM 结构、样式、行为与 Document DOM 隔离开,非常适合做组件的封装,因此它能成为 Web Component 的重要组成部分之一。
与Vue
、React
一样,Web Component
也提供了父传子的形式。
index.html:
<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">
这里传了3个props给组件,在组件中打印this
如下:
火眼金睛的我已经找到了在组件中接受传参的入口:
做一个简单的动态赋值:
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);
搞定~
HTML 模板的另一个好处是可以像 Vue
一样使用 <slot>
。比如,现在我们可以在这个 <trace-ele>
最下面添加一个插槽:
<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>
这样我们就可以实现自定义插槽内容了。
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);
上面主要给大家分享了一下 Web Component 的一些使用方法。总的来说,Web Component 是一系列 API 的组合:
它看起来仿佛是现在主流框架的基建实现,框架也正是基于原生的能力实现出一整套的解决方案,就比如Vue的响应式以来追踪、模板语法数据绑定,都是我们希望看到的。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。