介绍
Custom Elements 是 Web Components 标准的一部分,它允许我们自定义 HTML 元素并在网页中使用。使用 Custom Elements 可以让我们构建可扩展、可重用的应用程序,提高代码的模块化程度和可维护性。
本文将介绍如何使用 Custom Elements 构建可扩展应用的技巧,包括如何定义和使用 Custom Elements,如何使用 Shadow DOM 和 CSS 变量进行样式隔离和定制,以及如何通过事件和属性进行组件间通信。
定义 Custom Elements
定义 Custom Elements 需要使用 customElements.define 方法,该方法接受两个参数:元素名称和元素类。元素名称需要使用短横线分隔的小写字母命名,例如 my-element,元素类需要继承自 HTMLElement。
// www.javascriptcn.com code example
class MyElement extends HTMLElement {
constructor() {
super();
// ...
}
connectedCallback() {
// ...
}
disconnectedCallback() {
// ...
}
static get observedAttributes() {
return ['attr1', 'attr2'];
}
attributeChangedCallback(name, oldValue, newValue) {
// ...
}
}
customElements.define('my-element', MyElement);在元素类中,我们可以定义构造函数、生命周期方法和属性监听器等。其中,connectedCallback 和 disconnectedCallback 方法分别在元素被插入和移除文档树时调用,observedAttributes 方法返回需要监听的属性名,attributeChangedCallback 方法在监听的属性值变化时调用。
使用 Shadow DOM 和 CSS 变量
使用 Shadow DOM 可以将元素的样式和结构隔离,避免样式冲突和结构泄露。使用 CSS 变量可以让我们在应用中定义主题和样式变量,方便定制和维护。
// 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;
padding: var(--padding, 10px);
background-color: var(--bg-color, #fff);
color: var(--text-color, #333);
}
::slotted(*) {
margin: var(--margin, 10px);
}
`;
const slot = document.createElement('slot');
shadow.appendChild(style);
shadow.appendChild(slot);
}
}在元素的构造函数中,我们使用 this.attachShadow 方法创建 Shadow DOM,并定义样式和插槽节点。在样式中,我们使用 :host 选择器表示元素本身,使用 ::slotted(*) 选择器表示插槽内容,使用 var() 函数引用 CSS 变量。
组件间通信
组件间通信可以通过事件和属性进行。使用事件可以让组件触发和监听自定义事件,实现松耦合的通信方式。使用属性可以让组件通过属性值传递数据,实现紧耦合的通信方式。
// www.javascriptcn.com code example
class MyElement extends HTMLElement {
constructor() {
super();
this.addEventListener('click', () => {
const event = new CustomEvent('my-event', {
detail: { data: 'hello' },
bubbles: true,
composed: true,
});
this.dispatchEvent(event);
});
}
static get observedAttributes() {
return ['prop1'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'prop1') {
this.dispatchEvent(new CustomEvent('prop1-changed', {
detail: { value: newValue },
bubbles: true,
composed: true,
}));
}
}
get prop1() {
return this.getAttribute('prop1');
}
set prop1(value) {
this.setAttribute('prop1', value);
}
}在元素中,我们可以通过 this.dispatchEvent 方法触发自定义事件,并通过 CustomEvent 构造函数传递事件数据。在监听事件时,我们可以通过 this.addEventListener 方法添加事件监听器,通过 event.detail 属性获取事件数据。在监听属性时,我们可以通过 static get observedAttributes 方法定义需要监听的属性名,通过 attributeChangedCallback 方法在属性值变化时触发自定义事件。
示例代码
下面是一个使用 Custom Elements 构建可扩展应用的示例代码:
// www.javascriptcn.com code example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Elements Demo</title>
</head>
<body>
<my-element></my-element>
<my-element prop1="value1"></my-element>
<my-element prop1="value2">
<div slot="content">Content</div>
</my-element>
<script>
class MyElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const style = document.createElement('style');
style.textContent = `
:host {
display: block;
padding: var(--padding, 10px);
background-color: var(--bg-color, #fff);
color: var(--text-color, #333);
}
::slotted(*) {
margin: var(--margin, 10px);
}
`;
const slot = document.createElement('slot');
slot.name = 'content';
shadow.appendChild(style);
shadow.appendChild(slot);
this.addEventListener('click', () => {
const event = new CustomEvent('my-event', {
detail: { data: 'hello' },
bubbles: true,
composed: true,
});
this.dispatchEvent(event);
});
}
static get observedAttributes() {
return ['prop1'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'prop1') {
this.dispatchEvent(new CustomEvent('prop1-changed', {
detail: { value: newValue },
bubbles: true,
composed: true,
}));
}
}
get prop1() {
return this.getAttribute('prop1');
}
set prop1(value) {
this.setAttribute('prop1', value);
}
}
customElements.define('my-element', MyElement);
</script>
</body>
</html>在该示例代码中,我们定义了一个 my-element 元素,它包含一个插槽节点和一个点击事件。我们可以在 HTML 中使用 my-element 元素,并通过属性和插槽传递数据。在 JavaScript 中,我们可以监听 my-element 元素的自定义事件和属性变化事件,实现组件间通信。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/67da579fa941bf713424732f