Web Components 是一种用于创建可重用组件的技术,它包括自定义元素、Shadow DOM 和 HTML 模板等规范。使用 Web Components 可以更轻松地构建复杂的前端组件,并提高代码的可维护性和可复用性。
自定义元素
自定义元素是 Web Components 的核心,它允许我们创建自定义的 HTML 元素,并在页面中使用它们。自定义元素可以用 JavaScript 定义,并在 HTML 中使用,就像使用内置元素一样。
定义自定义元素
定义自定义元素需要使用 customElements.define() 方法,该方法接受两个参数:元素名称和元素类。
class MyElement extends HTMLElement {
constructor() {
super();
// 在构造函数中可以添加初始化逻辑等
}
}
customElements.define('my-element', MyElement);在上面的代码中,我们定义了一个名为 MyElement 的自定义元素,并将其注册为 my-element 标签。
使用自定义元素
在 HTML 中使用自定义元素时,只需要像使用内置元素一样添加标签即可。
<my-element></my-element>
在浏览器中打开该页面后,就会看到一个空的 my-element 元素。
自定义元素的生命周期方法
自定义元素的生命周期方法包括 connectedCallback()、disconnectedCallback()、adoptedCallback() 和 attributeChangedCallback()。
其中,connectedCallback() 在元素被插入到文档中时调用,disconnectedCallback() 在元素从文档中移除时调用,adoptedCallback() 在元素被移动到新文档时调用,attributeChangedCallback() 在元素的属性值发生变化时调用。
// www.javascriptcn.com code example
class MyElement extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
console.log('元素被插入到文档中');
}
disconnectedCallback() {
console.log('元素从文档中移除');
}
adoptedCallback() {
console.log('元素被移动到新文档');
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(`属性 ${name} 的值从 ${oldValue} 变为 ${newValue}`);
}
}
customElements.define('my-element', MyElement);在上面的代码中,我们为 MyElement 类添加了生命周期方法,并在其中打印了一些信息。当我们在 HTML 中使用 my-element 标签时,这些生命周期方法会自动被调用。
Shadow DOM
Shadow DOM 是一种用于封装 HTML 和 CSS 的技术,它允许我们创建独立的 DOM 和 CSS 树,并将其嵌入到文档中。使用 Shadow DOM 可以避免样式和结构上的冲突,并提高组件的可重用性。
创建 Shadow DOM
创建 Shadow DOM 需要使用 attachShadow() 方法,该方法接受一个参数:{mode: 'open'} 或 {mode: 'closed'},表示 Shadow DOM 的开放或封闭状态。
class MyElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
// 在 shadow 中添加 DOM 和 CSS
}
}在上面的代码中,我们使用 attachShadow() 方法创建了一个开放的 Shadow DOM,并将其保存在 shadow 变量中。
在 Shadow DOM 中添加 DOM 和 CSS
在 Shadow DOM 中添加 DOM 和 CSS 可以使用常规的 DOM 和 CSS 操作,只需要将它们添加到 shadow 变量中即可。
// www.javascriptcn.com code example
class MyElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const div = document.createElement('div');
div.textContent = 'Hello, World!';
shadow.appendChild(div);
const style = document.createElement('style');
style.textContent = `
div {
color: red;
}
`;
shadow.appendChild(style);
}
}在上面的代码中,我们在 Shadow DOM 中添加了一个红色的 div 元素,并设置了其文本内容为 Hello, World!。
在 Shadow DOM 中使用事件
在 Shadow DOM 中使用事件需要使用 composed: true 选项,该选项表示事件可以穿过 Shadow DOM 边界。
// www.javascriptcn.com code example
class MyElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const button = document.createElement('button');
button.textContent = 'Click me';
button.addEventListener('click', event => {
const customEvent = new CustomEvent('my-event', {composed: true});
this.dispatchEvent(customEvent);
});
shadow.appendChild(button);
}
}在上面的代码中,我们在 Shadow DOM 中添加了一个按钮,并为其添加了一个点击事件。当点击按钮时,会创建一个名为 my-event 的自定义事件,并通过 this.dispatchEvent() 方法派发出去。
Slot
Slot 是一种用于插入内容的技术,它允许我们在组件内部定义插槽,并在使用组件时填充内容。使用 Slot 可以提高组件的灵活性和可重用性。
定义插槽
定义插槽需要使用 <slot> 标签,该标签可以设置 name 属性,表示插槽名称。
<template>
<div>
<h1><slot name="title">Default Title</slot></h1>
<p><slot name="content">Default Content</slot></p>
</div>
</template>在上面的代码中,我们在组件的模板中定义了两个插槽:title 和 content。如果在使用组件时没有填充内容,则会显示默认值。
填充插槽
填充插槽需要使用 <slot> 标签,该标签可以设置 name 属性,表示要填充的插槽名称。
<my-component> <h1 slot="title">Title</h1> <p slot="content">Content</p> </my-component>
在上面的代码中,我们使用 my-component 标签,并为其填充了 title 和 content 两个插槽。在组件中,插槽的内容会替换掉默认值。
实践示例
下面是一个使用 Web Components 技术实现的计数器组件示例代码:
// www.javascriptcn.com code example
<template id="counter-template">
<style>
.counter {
display: flex;
align-items: center;
}
.button {
border: 1px solid #ccc;
padding: 5px 10px;
cursor: pointer;
}
.count {
margin: 0 10px;
}
</style>
<div class="counter">
<button class="button" id="decrement">-</button>
<span class="count">0</span>
<button class="button" id="increment">+</button>
</div>
</template>
<script>
class Counter extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const template = document.querySelector('#counter-template');
const content = template.content.cloneNode(true);
shadow.appendChild(content);
this.countElement = shadow.querySelector('.count');
shadow.querySelector('#decrement').addEventListener('click', () => {
this.count--;
this.updateCount();
});
shadow.querySelector('#increment').addEventListener('click', () => {
this.count++;
this.updateCount();
});
}
connectedCallback() {
this.count = parseInt(this.getAttribute('count')) || 0;
this.updateCount();
}
updateCount() {
this.countElement.textContent = this.count;
}
}
customElements.define('my-counter', Counter);
</script>在上面的代码中,我们使用 <template> 标签定义了计数器组件的模板,并在其中使用了 Shadow DOM 和 Slot 技术。在 JavaScript 中,我们定义了一个名为 Counter 的自定义元素,并为其添加了生命周期方法和计数器逻辑。最后,我们使用 customElements.define() 方法将 Counter 类注册为 my-counter 标签。
在 HTML 中使用该组件只需要添加一个 my-counter 标签即可:
<my-counter count="10"></my-counter>
在浏览器中打开该页面后,就会看到一个初始值为 10 的计数器组件。点击加号或减号按钮可以增加或减少计数器的值。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d58700a941bf7134a6921e