组件编程二
内容纲要
WEB一直在往自然言语化方向发展,而组件则是自然语言化很好的方式和体现。
自定义组件
与React或Angular相似,一切自定义标签都继承HTMLElement类:
class WaHaha extends HTMLElement {
connectedCallback() {
this.innerHTML = `Hello Indeex`;
}
}
customElements.define('wa-haha', WaHaha);
注意this指向。
组件生命周期
生命周期是组件的基本功能,当组件从加载到渲染完成,每一步都可以控制:
class WaHaha extends HTMLElement {
static get observedAttributes() {
return ['open'];
}
attributeChangedCallback(attrName, oldValue, newValue) {
if (newValue !== oldValue) {
this[attrName] = this.hasAttribute(attrName);
}
}
connectedCallback() {
const template = document.getElementById('wa-haha');
const node = document.importNode(template.content, true);
this.appendChild(node);
}
}
observedAttributes初始化或者更新时调用
attributeChangedCallback属性更改回调
connectedCallback初始化设置、元素更新回调
以下示例禁止用于实际项目:
<style type="text/css">
#modalBtn {
background: tomato;
border-radius: 2ch;
color: #fff;
padding: 5ch 3ch;
position: static;
}
</style>
<wa-haha></wa-haha>
<template id="wahaha-template">
<style>
.wrapper {
opacity: 0;
transition: visibility 0s, opacity 0.25s ease-in;
}
.wrapper:not(.open) {
visibility: hidden;
}
.wrapper.open {
align-items: center;
display: flex;
justify-content: center;
height: 100vh;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 1;
visibility: visible;
}
.overlay {
background: rgba(0, 0, 0, 0.8);
height: 100%;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
}
.dialog {
background: #ffffff;
max-width: 800px;
padding: 1rem;
position: fixed;
border-radius: 20px;
}
button {
all: unset;
cursor: pointer;
font-size: 1.25rem;
position: absolute;
top: 1rem;
right: 1rem;
}
button{
box-sizing: border-box;
}
button:focus{
border: none;
}
button:hover{
border: 1px solid #1E9BF9;
}
</style>
<div class="wrapper">
<div class="overlay"></div>
<div class="dialog" role="dialog" aria-labelledby="title" aria-describedby="content">
<button class="close" aria-label="Close">叉️</button>
<h1 id="title">Hello Indeex</h1>
<div id="content" class="content">
<p>哇哈哈的模态窗</p>
</div>
</div>
</div>
</template>
<button id="modalBtn">假装是个编辑按钮</button>
class WaHaha extends HTMLElement {
static get observedAttributes() {
return ['open'];
}
constructor() {
super();
this.close = this.close.bind(this);
this._watchEscape = this._watchEscape.bind(this);
}
attributeChangedCallback(attrName, oldValue, newValue) {
if (oldValue !== newValue) {
this[attrName] = this.hasAttribute(attrName);
}
}
connectedCallback() {
const template = document.getElementById('wahaha-template');
const node = document.importNode(template.content, true);
this.appendChild(node);
this.querySelector('button').addEventListener('click', this.close);
this.querySelector('.overlay').addEventListener('click', this.close);
this.open = this.open;
}
disconnectedCallback() {
this.querySelector('button').removeEventListener('click', this.close);
this.querySelector('.overlay').removeEventListener('click', this.close);
}
get open() {
return this.hasAttribute('open');
}
set open(isOpen) {
this.querySelector('.wrapper').classList.toggle('open', isOpen);
this.querySelector('.wrapper').setAttribute('aria-hidden', !isOpen);
if (isOpen) {
this._wasFocused = document.activeElement;
this.setAttribute('open', '');
document.addEventListener('keydown', this._watchEscape);
this.focus();
this.querySelector('button').focus();
} else {
this._wasFocused && this._wasFocused.focus && this._wasFocused.focus();
this.removeAttribute('open');
document.removeEventListener('keydown', this._watchEscape);
this.close();
}
}
close() {
if (this.open !== false) {
this.open = false;
}
const closeEvent = new CustomEvent('wahaha-closed');
this.dispatchEvent(closeEvent);
}
_watchEscape(event) {
if (event.key === 'Escape') {
this.close();
}
}
}
customElements.define('wa-haha', WaHaha);
const button = document.getElementById('modalBtn');
button.addEventListener('click', () => {
document.querySelector('wa-haha').open = true;
})
演示地址:自定义组件
当然,也可以定义纯逻辑组件:
class Ehehe extends HTMLElement {
connectedCallback() {
this._onEheheClosed = this._onEheheClosed.bind(this);
this.addEventListener('ehehe-closed', this._onEheheClosed);
}
get ehehes() {
return Array.from(this.querySelectorAll('one-ehehe'));
}
_onEheheClosed(event) {
const eheheClosed = event.target;
const nextIndex = this.ehehes.indexOf(eheheClosed);
if (nextIndex !== -1) {
this.ehehes[nextIndex].open = true;
}
}
}
这个和React很类似。。
code enjoy!😜😜😜
作者:indeex
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。