什么是 Web Components?
Web Components 是一种用于开发可重用组件的技术,它由三个主要规范组成:Custom Elements、Shadow DOM 和 HTML Templates。这些规范允许我们创建自定义 HTML 元素并在其中封装样式和行为。
为什么要使用 Web Components?
Web Components 帮助我们解决了两个主要问题:可复用性和封装性。
可复用性:Web Components 允许我们创建通用的 UI 组件,这些组件可以在不同的项目、不同的页面和不同的框架中重复使用,避免了代码复制和粘贴的问题。
封装性:Web Components 可以封装复杂的行为和样式,并通过一个简单的自定义标签来使用它们。这样我们就可以将一些复杂的 UI 组件封装成一个简单的标签,让其他开发者可以更容易地使用它们。
如何开发 Web Components?
步骤一:创建 Custom Element
Custom Element 是 Web Components 中最重要的概念,它允许我们创建自定义的 HTML 元素。
class MyElement extends HTMLElement {
constructor() {
super();
}
}
customElements.define('my-element', MyElement);上面的代码定义了一个名为 my-element 的 Custom Element。
步骤二:添加 Shadow DOM
Shadow DOM 是 Web Components 中用于封装样式和行为的技术,它允许我们创建一个“影子 DOM”,独立于文档的主要 DOM。
// www.javascriptcn.com code example
class MyElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const style = document.createElement('style');
style.textContent = `
:host {
display: block;
}
`;
shadow.appendChild(style);
const content = document.createElement('div');
content.textContent = 'Hello, World!';
shadow.appendChild(content);
}
}
customElements.define('my-element', MyElement);上面的代码添加了一个 Shadow DOM,并在其中包含了一个样式和一个 div 元素。
步骤三:使用 HTML Templates
HTML Templates 允许我们将一段 HTML 代码包装起来,并在需要时将其实例化。
// www.javascriptcn.com code example
class MyElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
display: block;
}
</style>
<div>
<slot name="header"></slot>
<div id="content">
<slot></slot>
</div>
<slot name="footer"></slot>
</div>
`;
shadow.appendChild(template.content.cloneNode(true));
}
}
customElements.define('my-element', MyElement);上面的代码使用了一个 HTML Template,并在其中引用了三个插槽。
步骤四:使用插槽
插槽允许我们在 Web Components 中定义可变的区域,使其可以根据需要进行替换。
<my-element> <div slot="header">Hello</div> <div>World</div> <button slot="footer">Click me</button> </my-element>
上面的代码在 my-element 中使用了三个插槽,分别为 header、default 和 footer。
示例:实现一个可复用的弹框组件
// www.javascriptcn.com code example
class ModalDialog extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 99999;
display: flex;
align-items: center;
justify-content: center;
}
#modal-container {
border-radius: 3px;
box-shadow: 0 0 10px rgba(0, 0, 0, .1);
background-color: #fff;
max-width: 800px;
max-height: 600px;
overflow: auto;
display: flex;
flex-direction: column;
}
#header {
padding: 10px;
border-bottom: 1px solid #eee;
}
#content {
padding: 10px;
flex: 1;
}
#footer {
padding: 10px;
border-top: 1px solid #eee;
display: flex;
justify-content: flex-end;
}
</style>
<div id="modal-container">
<div id="header">
<slot name="header"></slot>
</div>
<div id="content">
<slot></slot>
</div>
<div id="footer">
<slot name="footer"></slot>
<button id="cancel">Cancel</button>
<button id="confirm">Confirm</button>
</div>
</div>
`;
shadow.appendChild(template.content.cloneNode(true));
const cancelButton = shadow.querySelector('#cancel');
cancelButton.addEventListener('click', () => {
this.close();
});
const confirmButton = shadow.querySelector('#confirm');
confirmButton.addEventListener('click', () => {
this.done();
});
}
connectedCallback() {
const modal = document.createElement('div');
modal.id = 'backdrop';
modal.addEventListener('click', () => {
this.close();
});
document.body.appendChild(modal);
}
disconnectedCallback() {
const modal = document.querySelector('#backdrop');
if (modal) {
modal.removeEventListener('click', () => {
this.close();
});
modal.remove();
}
}
open() {
const modal = this.shadowRoot.querySelector('#modal-container');
modal.style.display = 'block';
}
close() {
const modal = this.shadowRoot.querySelector('#modal-container');
modal.style.display = 'none';
}
done() {
const event = new CustomEvent('done');
this.dispatchEvent(event);
this.close();
}
}
customElements.define('modal-dialog', ModalDialog);上面的代码定义了一个名为 modal-dialog 的 Custom Element,它有一个 open 方法用于打开弹框,一个 close 方法用于关闭弹框,一个 done 方法用于完成操作并关闭弹框,以及三个插槽:header、default 和 footer。
<modal-dialog> <div slot="header">Hello</div> <div>World</div> <button slot="footer">Cancel</button> <button slot="footer">Save</button> </modal-dialog>
上面的代码使用了 modal-dialog 组件,并在其中使用了三个插槽,并为 footer 插槽指定了两个按钮。
总结
Web Components 是一种非常强大的技术,在 UI 组件的重用性和封装性方面具有很大的优势。但是它仍然是一个相对较新的技术,需要浏览器和框架的支持。在开发时,我们建议使用现有的 Web Components 库或框架,例如 Polymer 或 Stencil,以快速地创建可复用的 UI 组件。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/65b01e9cadd4f0e0ff98a843