由于最近作者在学习微前端,web component也是其中一大特性,部分微前端框架使用到,也是深入学习了一下相关的知识,分享出来。
Web Component 实际上一系列技术的组合,主要包含 3 部分:
在一份html文件中的一个web component看起来是这样的:
<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件"" data-textnode-index-1701072719744="25" data-index-1701072719744="405" data-index-len-1701072719744="405" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <div slot="slot-ele"" data-textnode-index-1701072719744="28" data-index-1701072719744="428" data-index-len-1701072719744="428" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>插槽内容</div" data-textnode-index-1701072719744="29" data-index-1701072719744="438" data-index-len-1701072719744="438" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">></trace-ele" data-textnode-index-1701072719744="31" data-index-1701072719744="450" data-index-len-1701072719744="450" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
看起来很像Vue吧?接下来让我们一个个demo学习web component。
由于Web Component亲和原生,因此无需其他包的依赖,一个index.html和一个index.js即可体验学习。
我们直接写一个html模板,文章的案例组件统称为<trace-ele />
index.html:
<body" data-textnode-index-1701072719744="48" data-index-1701072719744="606" data-index-len-1701072719744="606" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <template id="trace"" data-textnode-index-1701072719744="56" data-index-1701072719744="628" data-index-len-1701072719744="628" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <div class="container"" data-textnode-index-1701072719744="64" data-index-1701072719744="657" data-index-len-1701072719744="657" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <img class="image" src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp" alt="" /" data-textnode-index-1701072719744="80" data-index-1701072719744="806" data-index-len-1701072719744="806" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="title"" data-textnode-index-1701072719744="88" data-index-1701072719744="831" data-index-len-1701072719744="831" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>学习Web Component</p" data-textnode-index-1701072719744="92" data-index-1701072719744="850" data-index-len-1701072719744="850" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="desc"" data-textnode-index-1701072719744="100" data-index-1701072719744="874" data-index-len-1701072719744="874" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>Web Component是微前端沙盒隔离原理的重要知识</p" data-textnode-index-1701072719744="104" data-index-1701072719744="906" data-index-len-1701072719744="906" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="price"" data-textnode-index-1701072719744="112" data-index-1701072719744="931" data-index-len-1701072719744="931" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>¥25.00</p" data-textnode-index-1701072719744="116" data-index-1701072719744="941" data-index-len-1701072719744="941" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> </div" data-textnode-index-1701072719744="120" data-index-1701072719744="953" data-index-len-1701072719744="953" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> </template" data-textnode-index-1701072719744="124" data-index-1701072719744="968" data-index-len-1701072719744="968" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <trace-ele /" data-textnode-index-1701072719744="128" data-index-1701072719744="985" data-index-len-1701072719744="985" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <script src="./index.js" /" data-textnode-index-1701072719744="136" data-index-1701072719744="1016" data-index-len-1701072719744="1016" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">></body" data-textnode-index-1701072719744="139" data-index-1701072719744="1023" data-index-len-1701072719744="1023" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
这里我们写了一个"模板"——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" data-textnode-index-1701072719744="209" data-index-1701072719744="1590" data-index-len-1701072719744="1590" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <template id="trace"" data-textnode-index-1701072719744="217" data-index-1701072719744="1612" data-index-len-1701072719744="1612" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <div class="container"" data-textnode-index-1701072719744="225" data-index-1701072719744="1641" data-index-len-1701072719744="1641" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <img class="image" src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp" alt="" /" data-textnode-index-1701072719744="241" data-index-1701072719744="1790" data-index-len-1701072719744="1790" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="title"" data-textnode-index-1701072719744="249" data-index-1701072719744="1815" data-index-len-1701072719744="1815" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>学习Web Component</p" data-textnode-index-1701072719744="253" data-index-1701072719744="1834" data-index-len-1701072719744="1834" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="desc"" data-textnode-index-1701072719744="261" data-index-1701072719744="1858" data-index-len-1701072719744="1858" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>Web Component是微前端沙盒隔离原理的重要知识</p" data-textnode-index-1701072719744="265" data-index-1701072719744="1890" data-index-len-1701072719744="1890" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="price"" data-textnode-index-1701072719744="273" data-index-1701072719744="1915" data-index-len-1701072719744="1915" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>¥25.00</p" data-textnode-index-1701072719744="277" data-index-1701072719744="1925" data-index-len-1701072719744="1925" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> </div" data-textnode-index-1701072719744="281" data-index-1701072719744="1937" data-index-len-1701072719744="1937" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <style" data-textnode-index-1701072719744="286" data-index-1701072719744="1956" data-index-len-1701072719744="1956" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .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" data-textnode-index-1701072719744="391" data-index-1701072719744="2574" data-index-len-1701072719744="2574" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> </template" data-textnode-index-1701072719744="395" data-index-1701072719744="2589" data-index-len-1701072719744="2589" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <trace-ele /" data-textnode-index-1701072719744="399" data-index-1701072719744="2606" data-index-len-1701072719744="2606" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <script src="./index.js" /" data-textnode-index-1701072719744="407" data-index-1701072719744="2637" data-index-len-1701072719744="2637" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">></body" data-textnode-index-1701072719744="410" data-index-1701072719744="2644" data-index-len-1701072719744="2644" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
样式生效:
图片
但是这里如果给一个通用标签的样式,就像这样:
<body" data-textnode-index-1701072719744="416" data-index-1701072719744="2686" data-index-len-1701072719744="2686" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p" data-textnode-index-1701072719744="420" data-index-1701072719744="2693" data-index-len-1701072719744="2693" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>组件外的P标签</p" data-textnode-index-1701072719744="424" data-index-1701072719744="2704" data-index-len-1701072719744="2704" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <template" data-textnode-index-1701072719744="428" data-index-1701072719744="2722" data-index-len-1701072719744="2722" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p" data-textnode-index-1701072719744="432" data-index-1701072719744="2733" data-index-len-1701072719744="2733" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>组件中的P标签</p" data-textnode-index-1701072719744="436" data-index-1701072719744="2744" data-index-len-1701072719744="2744" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <style" data-textnode-index-1701072719744="440" data-index-1701072719744="2759" data-index-len-1701072719744="2759" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> p { color: red; } ... .container {} </style" data-textnode-index-1701072719744="455" data-index-1701072719744="2865" data-index-len-1701072719744="2865" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> </template" data-textnode-index-1701072719744="459" data-index-1701072719744="2884" data-index-len-1701072719744="2884" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">></body" data-textnode-index-1701072719744="462" data-index-1701072719744="2891" data-index-len-1701072719744="2891" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
效果如下:
图片
可以看到组件外的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="原生态自带隔离的组件"" data-textnode-index-1701072719744="551" data-index-1701072719744="3716" data-index-len-1701072719744="3716" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
这里传了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 " data-textnode-index-1701072719744="593" data-index-1701072719744="4043" data-index-len-1701072719744="4043" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .title').textContent = this.getAttribute('name'); cloneEle.querySelector('.container " data-textnode-index-1701072719744="600" data-index-1701072719744="4133" data-index-len-1701072719744="4133" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .price').textContent = this.getAttribute('version'); cloneEle.querySelector('.container " data-textnode-index-1701072719744="607" data-index-1701072719744="4226" data-index-len-1701072719744="4226" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .desc').textContent = this.getAttribute('desc'); this.shadowRoot.appendChild(cloneEle); }}customElements.define("trace-ele", Trace);
搞定~
HTML 模板的另一个好处是可以像 Vue 一样使用 <slot>。比如,现在我们可以在这个 <trace-ele> 最下面添加一个插槽:
<body" data-textnode-index-1701072719744="632" data-index-1701072719744="4445" data-index-len-1701072719744="4445" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <template id="trace"" data-textnode-index-1701072719744="640" data-index-1701072719744="4470" data-index-len-1701072719744="4470" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <div class="container"" data-textnode-index-1701072719744="648" data-index-1701072719744="4501" data-index-len-1701072719744="4501" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p" data-textnode-index-1701072719744="652" data-index-1701072719744="4516" data-index-len-1701072719744="4516" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>组件中的P标签</p" data-textnode-index-1701072719744="656" data-index-1701072719744="4527" data-index-len-1701072719744="4527" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <img class="image" src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp" alt="" /" data-textnode-index-1701072719744="672" data-index-1701072719744="4696" data-index-len-1701072719744="4696" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="title"" data-textnode-index-1701072719744="680" data-index-1701072719744="4725" data-index-len-1701072719744="4725" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>学习Web Component</p" data-textnode-index-1701072719744="684" data-index-1701072719744="4744" data-index-len-1701072719744="4744" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="desc"" data-textnode-index-1701072719744="692" data-index-1701072719744="4772" data-index-len-1701072719744="4772" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>Web Component是微前端沙盒隔离原理的重要知识</p" data-textnode-index-1701072719744="696" data-index-1701072719744="4804" data-index-len-1701072719744="4804" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <p class="price"" data-textnode-index-1701072719744="704" data-index-1701072719744="4833" data-index-len-1701072719744="4833" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>¥25.00</p" data-textnode-index-1701072719744="708" data-index-1701072719744="4843" data-index-len-1701072719744="4843" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <slot name="slot-ele"" data-textnode-index-1701072719744="716" data-index-1701072719744="4877" data-index-len-1701072719744="4877" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">></slot" data-textnode-index-1701072719744="719" data-index-1701072719744="4884" data-index-len-1701072719744="4884" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> </div" data-textnode-index-1701072719744="723" data-index-1701072719744="4898" data-index-len-1701072719744="4898" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <style" data-textnode-index-1701072719744="727" data-index-1701072719744="4913" data-index-len-1701072719744="4913" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> ... </style" data-textnode-index-1701072719744="732" data-index-1701072719744="4940" data-index-len-1701072719744="4940" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> </template" data-textnode-index-1701072719744="736" data-index-1701072719744="4955" data-index-len-1701072719744="4955" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件"" data-textnode-index-1701072719744="752" data-index-1701072719744="5024" data-index-len-1701072719744="5024" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> <div slot="slot-ele"" data-textnode-index-1701072719744="760" data-index-1701072719744="5053" data-index-len-1701072719744="5053" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>插槽内容</div" data-textnode-index-1701072719744="764" data-index-1701072719744="5063" data-index-len-1701072719744="5063" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> </trace-ele" data-textnode-index-1701072719744="768" data-index-1701072719744="5079" data-index-len-1701072719744="5079" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">></body" data-textnode-index-1701072719744="771" data-index-1701072719744="5086" data-index-len-1701072719744="5086" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">>
这样我们就可以实现自定义插槽内容了。
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 " data-textnode-index-1701072719744="812" data-index-1701072719744="5401" data-index-len-1701072719744="5401" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> .title") .addEventListener("click", this.onClick); this.shadowRoot.appendChild(cloneEle); } onClick = () =" data-textnode-index-1701072719744="825" data-index-1701072719744="5519" data-index-len-1701072719744="5519" class="" style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; display: inline-block; text-indent: initial;">> { alert("Click Me!"); };}customElements.define("trace-ele", Trace);
图片
上面主要给大家分享了一下 Web Component 的一些使用方法。总的来说,Web Component 是一系列 API 的组合:
它看起来仿佛是现在主流框架的基建实现,框架也正是基于原生的能力实现出一整套的解决方案,就比如Vue的响应式以来追踪、模板语法数据绑定,都是我们希望看到的。
本文链接:http://www.28at.com/showinfo-26-34618-0.html一文读懂Web Component
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com