# Web Components
Web Components是一套原生的,允许我们自定义一套可重用有相应功能的元素的组件。
利用它,可以实现类似vue组件的可复用模块。
缺点: 兼容不好
相关知识:
1. Custom Element: 自定义元素
customElements的通过define方法来自定义元素
- 接受两个参数
- 第一个参数,自定义元素名
- 第二个元素,自定义元素的模板对象
- 例子: customElements.define('test-button', TestButton)
2. shadow Dom(影子DOM): 影子DOM将我们的自定义元素封装起来,并插入到文档中(影子dom中的内容是跟主文档隔开的)
3. template(模板)和 slot(插槽)
---
## 创建一个web Components的具体流程
1. 创建两个模板test-collapse 和 test-collapse-item
<template id="test-collapse">
<slot></slot>
</template>
<template id="test-collapse-item">
<div class="title">title内容</div>
<div class="content"><slot></slot></div>
</template>
2. 根据模板创建shadow Dom并使其在文档中生效
难点: 是需要知道相关的api
// 定义需要监听的属性
// 比如监听active属性的变化
static get observedAttributes() {
return ['active'];
}
// 生命周期函数,监听的属性变化时触发
attributeChangedCallback(key, oldValue, newValue) {
if(key === 'active') {
this.activeList = JSON.parse(newValue)
// 属性变化后,触发自定义的方法
this.render()
}
}
// 父组件传值给子组件是通过设置子组件的属性,子组件监听属性变化即可
// 子组件传值给父组件,是通过派发父组件的自定义事件
- 父组件自定义监听事件
testCollapse.addEventListener('nameChange', (e) => {
let {isShow, name} = e.detail
if(isShow) {
let index = defaultAtiveList.indexOf(name)
if(index != -1) {
defaultAtiveList.splice(index, 1)
}
} else {
defaultAtiveList.push(name)
}
testCollapse.setAttribute('active', JSON.stringify(defaultAtiveList))
})
- 子组件派发事件
document.querySelector('test-collapse').dispatchEvent(new CustomEvent('nameChange', {
detail: {
name: that.name,
isShow: that.isShow
}
}))
TestCollapse
class TestCollapse extends HTMLElement {
// 定义需要监听的属性
static get observedAttributes() {
return ['active'];
}
constructor() {
super()
// 创建shadow dom
var shadow = this.attachShadow({mode: 'open'});
// attachShadow函数的mode配置有两个值可选 open|close
// open 表示可以通过页面内的 JavaScript 方法来获取 Shadow DOM
// 获取模板
var tempTmp = document.querySelector('#test-collapse')
// 拷贝模板内容
// template.content可以获取到模板的内容
var cloneTemp = tempTmp.content.cloneNode(true) // 传参true是不单只拷贝子元素,而且还拷贝模板元素本身
var style = document.createElement('style')
style.textContent = `
test-collapse {
display: flex;
flex-direction: column;
}
`
shadow.appendChild(cloneTemp)
shadow.appendChild(style)
this.activeList = []
// 监听slot插槽内容的变化,插槽内容变化,更新内容
shadow.addEventListener('slotchange', ()=> {
this.render()
})
}
// 生命周期函数,监听的属性变化时触发
attributeChangedCallback(key, oldValue, newValue) {
if(key === 'active') {
this.activeList = JSON.parse(newValue)
// 属性变化后,触发自定义的方法
this.render()
}
}
render() {
this.querySelectorAll('test-collapse-item').forEach(item => {
item.setAttribute('active', JSON.stringify(this.activeList))
})
}
}
TestCollapseItem
class TestCollapseItem extends HTMLElement {
static get observedAttributes() {
return ['active', 'title', 'name']
}
constructor() {
super()
var shadow = this.attachShadow({mode: 'open'});
// 获取模板
var tempTmp = document.querySelector('#test-collapse-item')
// 拷贝模板内容
// template.content可以获取到模板的内容
var cloneTemp = tempTmp.content.cloneNode(true) // 传参true是不单只拷贝子元素,而且还拷贝模板元素本身
var style = document.createElement('style')
style.textContent = `
.content {
background: #999;
}
`
shadow.appendChild(cloneTemp)
shadow.appendChild(style)
this.isShow = true
this.titleEle = shadow.querySelector('.title')
this.titleEle.addEventListener('click', () => {
let that = this
document.querySelector('test-collapse').dispatchEvent(new CustomEvent('nameChange', {
detail: {
name: that.name,
isShow: that.isShow
}
}))
})
}
attributeChangedCallback(key, oldValue, newValue) {
switch (key) {
case 'active':
this.activeList = JSON.parse(this.getAttribute(key))
break;
case 'title':
this.titleEle.innerHTML = this.getAttribute(key)
break;
case 'name':
this.name = this.getAttribute(key)
default:
break;
}
if(this.activeList && this.name) {
this.isShow = this.activeList.includes(this.name)
// this.shadowRoot获取影子dom的根元素
this.shadowRoot.querySelector('.content').style.display = this.isShow ? 'block': 'none'
}
}
}

Web Components提供了一套原生API,用于创建可复用的自定义元素,类似于Vue组件。主要涉及Custom Element、Shadow DOM和Template/Slot。Custom Element通过`customElements.define`定义,Shadow DOM用于封装组件并隔离样式。创建Web Components的流程包括创建模板、生成Shadow DOM以及处理属性监听和事件传递。由于兼容性问题,实际应用需注意浏览器支持。
357

被折叠的 条评论
为什么被折叠?



