Web Components 和 vue、react 都是基于组件化的形式去书写页面。
Web Components 的主要作用及特点:
Html:
<div class="page">
<div class="page__header">
<!-- 设置组件open属性 -->
<button class="page__header-button" onclick="drawer.setAttribute('open', '')"></button>
</div>
<div class="page__content"></div>
<!-- 使用定义的组件 -->
<app-drawer id="drawer">
<ul class="page__drawer">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</app-drawer>
</div>
<!-- 定义组件的模板,html、css -->
<template id="app-drawer-template">
<style>
/* :host 用于设置根级组件样式,外部定义的样式会覆盖此处定义的样式 */
:host {
position: absolute;
top: 0;
left: 0;
z-index: 2;
width: 200px;
height: 100%;
background-color: #2d2d2d;
transition: .3s ease;
}
:host(.close) {
transform: translate3d(-100%, 0, 0)
}
</style>
<!-- 内容插槽,和 Vue 类似 -->
<slot></slot>
<slot name="close">
<button id="close">关闭</button>
</slot>
</template>
Javascript:
class AppDrawer extends HTMLElement {
constructor() {
super()
this._handleClick = this._handleClick.bind(this)
this.close()
this._createShadowDOM()
this._handleEvent('add')
}
// 设置需要检测的属性,可用于初始化组件状态
static get observedAttributes() {
return ['open']
}
set isOpen (value) {
if (value) {
this.setAttribute('open', '')
} else {
this.removeAttribute('open')
}
}
get isOpen() {
return this.hasAttribute('open')
}
// 在observedAttributes里设置了检测的属性,修改了就会调用,相当于vue watch
attributeChangedCallback(name, oldValue, newValue) {
this.toggle()
}
// 元素插入到dom后调用
connectedCallback() {
}
// 元素移出dom后调用
disconnectedCallback() {
this.handleEvent('remove')
}
_createShadowDOM() {
const shadowRoot = this.attachShadow({ mode: 'open' })
const template = document.querySelector('#app-drawer-template')
const instance = template.content.cloneNode(true)
shadowRoot.appendChild(instance)
}
_handleEvent(action) {
// 通过 this.shadowRoot.querySelector 选择组件里的元素
const closeButton = this.shadowRoot.querySelector('#close')
if (closeButton) {
closeButton[`${action}EventListener`]('click', this._handleClick)
}
}
_handleClick () {
this.isOpen = false
}
open() {
this.classList.remove('close')
}
close() {
this.classList.add('close')
}
toggle() {
if (this.isOpen) {
this.open()
} else {
this.close()
}
}
}
// 定义组件
window.customElements.define('app-drawer', AppDrawer)
WebComponents 可以创建复用的组件。ShadowDom 隔离 dom、css 提高了可维护性,不用在担心命名重复的问题。所有的功能都是基于原生Api和浏览器实现的,不用配置各种npm包。但是在操作 dom 上还是和以前一样繁琐,需要 querySelector 获取 dom 元素,才能完成后面的操作,如果基于数据驱动来更新页面会比直接操作 dom 要更加简洁,可以少写很多代码。
https://developers.google.com/web/fundamentals/web-components/customelements?hl=zh-cn