前言:本文纯作者个人理解来讲述什么是web Components,说的不对的地方请指正。作者学习web components是为了学习MicroApp微前端。
webComponents的主要组成
1、Custom elements (自定义元素)
2、Shadow Dom (影子dom)
3、Html template (Html 模版)
一、自定义元素
白话文理解:我可以自定义一些html标签,但是这些标签的名称必须包含连词线,用来区分原生html元素。例如 <user-info></user-info> 不能写成 <userInfo></userInfo>
。
user-info 标签的具体实现
class UserInfo extends HTMLElement {
constructor(){
super();
this.attachShadow( { mode: 'open' } );
}
connectedCallback(){
// 生命周期函数 当自定义元素首次被插入文档 DOM 时,被调用
const container = document.createElement('div');
container.classList.add('test');
container.innerHTML=`<p class="name">Bain</p><p class="age">12</p>`
this.shadowRoot.append(container);
}
disconnectedCallback(){
//当自定义元素从文档dom中删除时被调用
}
adoptedCallback(){
// 当自定义元素被移动到新文档时被调用
}
attributeChangedCallback(){
// 当自定义元素 增加、删除、修改自身属性时被调用
}
}
告诉浏览器<user-info>元素与这个类关联
window.customElements.define('user-info',UserInfo)
二、影子dom
白话文理解:我不想让别人获取user-info 的shadowdom。这部分 DOM 默认与外部 DOM 隔离,内部任何代码都无法影响外部,外部代码也无法影响内部(例如:全局样式之类,获取dom节点之类)。这个就叫做影子dom 。
实现方式:
this.attachShadow({mode:'open'})
具体现象如下:
document.querySelector('.test'); // null 无法获取testdom节点
// 全局设置 test样式无效
三、template标签
白话文理解:在js中写dom会比较麻烦,所以使用template标签定义dom
上文可以改写为:
<template id="userInfoTemplate">
<div class="container">
<p class="name">Bain</p>
<p class="age">12</p>
</div>
</template>
class UserInfo extends HTMLElement {
constructor(){
super();
var shadow = this.attachShadow( { mode: 'open' } );
const ele = document.getElementById('userInfoTemplate');
const content = ele.content.cloneNode(true);
shadow.append(content);
}
}
自定义元素样式实现
:host{
// 表示当前自定义元素 <user-info></user-info> 自定义元素默认是行内元素
display: block;
}
:host([propertyName]){
// 自定义元素存在 propertyName 属性
background:red;
}
:host(.test){
// 自定义元素存在 test类名
background: black;
}
自定义元素通信
// html
<script type='module' src='./main.js' ></script>
<body>
<customer-father></customer-father>
</body>
// main.js
import CustomerFather form './father.js';
// father.js
import CustomerSon from './son.js'
class CustomerFather extends HTMLElement {
constructor(){
super();
this.attachShadow( { mode: 'open' } );
}
connectedCallback(){
this.render()
}
render(){
const ele = document.createElement('div');
ele.innerHTML=`<customer-son></customer-son>`
this.shadowRoot.append(ele)
}
change(){
console.log('执行CustomerFather')
// 执行子元素方法
this.shadowRoot.querySelector('customer-son').change();
}
}
window.customElements.define('customer-father',CustomerFather)
export default CustomerFather;
// son.js
class CustomerSon extends HTMLElement {
constructor(){
super();
this.attachShadow( { mode: 'open' } );
}
connectedCallback(){
this.render()
}
render(){
const ele = document.createElement('div');
ele.innerText=`我是子元素`
ele.onclick = ()=>{
console.dir(this.getRootNode())
this.getRootNode().host.change();
}
this.shadowRoot.append(ele)
}
change(){
console.log('执行CustomerSon')
}
}
window.customElements.define('customer-son',CustomerSon)
export default CustomerSon;