「JavaScript深入」Web Components:构建可重用的跨框架组件

Web Components

    • 什么是 Web Components?
    • Web Components 的三大核心技术
      • 1. Custom Elements(自定义元素)
        • 定义和注册自定义元素
      • 2. Shadow DOM(影子 DOM)
        • 封装与隔离
        • Shadow DOM 的模式
      • 3. HTML Templates(HTML 模板)
        • 模板定义与克隆
        • 在 Web Components 中使用模板
    • 使用 Slot 支持外部内容插入
    • 属性支持与监听
    • 自定义事件
    • 生命周期回调
    • Web Components 组件库:Lit
    • 为什么 Web Components 没有流行?
    • Web Components 的应用场景
    • 结论

在现代 Web 开发中,组件化开发已经成为一种主流趋势。无论是 React、Vue 还是 Angular,组件化开发都极大地提高了代码的可维护性和可重用性。然而,这些框架的组件通常只能在特定的框架生态中使用,跨框架的组件复用一直是一个挑战。Web Components 的出现为这一问题提供了一个原生解决方案。下面将深入探讨 Web Components 的核心概念、技术细节以及其在实际开发中的应用。


什么是 Web Components?

Web Components 是一组由浏览器原生支持的 Web 标准,允许开发者创建可重用、封装的自定义 HTML 元素。这些元素具有跨框架兼容性,可以无缝集成到原生 HTML、React、Vue 和 Angular 等各种 Web 开发环境中。Web Components 的核心目标是通过标准化的方式实现组件的封装和复用,从而减少对特定框架的依赖。


Web Components 的三大核心技术

Web Components 的实现依赖于以下三大核心技术:

  1. Custom Elements(自定义元素)
  2. Shadow DOM(影子 DOM)
  3. HTML Templates(HTML 模板)

接下来,我们将逐一详细介绍这些技术。

1. Custom Elements(自定义元素)

Custom Elements 允许开发者定义自定义的 HTML 标签,并为其附加特定的行为。这些自定义标签可以像原生 HTML 元素一样使用,并接受属性和事件。

定义和注册自定义元素
  • 定义元素: 定义一个 JavaScript 类,该类继承自 HTMLElement,并在其中定义元素的特定行为

  • 注册元素: 通过 customElements.define() 方法注册自定义标签,并将其与定义的类绑定

    class MyElement extends HTMLElement {constructor() {super();// 初始化逻辑}connectedCallback() {this.innerHTML = `<p>Hello, World!</p>`;}
    }// 注册自定义元素
    customElements.define('my-element', MyElement);
    

    👆 我们定义了一个名为 my-element 的自定义元素,并在 connectedCallback 生命周期钩子中设置了其内容。当该元素被插入到 DOM 中时,connectedCallback 方法会被调用,从而渲染出 <p>Hello, World!</p>

2. Shadow DOM(影子 DOM)

Shadow DOM 提供了一种将组件的样式和结构进行封装和隔离的方法。通过使用 Shadow DOM,组件可以避免样式污染或被外部影响。

封装与隔离

Shadow DOM 为组件创建了一个私有的子 DOM 树,外部页面的 CSS 不会影响到其样式。这种封装机制使得组件的样式和行为可以完全独立于外部环境。

class MyElement extends HTMLElement {constructor() {super();const shadow = this.attachShadow({ mode: 'open' });shadow.innerHTML = `<style>p {color: blue;}</style><p>Hello, Shadow DOM!</p>`;}
}customElements.define('my-shadow-element', MyElement);

👆 我们创建了一个带有 Shadow DOM 的自定义元素。attachShadow({ mode: 'open' }) 方法创建了一个开放的 Shadow DOM,外部 JavaScript 可以通过 element.shadowRoot 访问和操作 Shadow DOM 中的内容。

Shadow DOM 的模式
  • open:创建的 Shadow DOM 可以通过 JavaScript 直接访问和操作。
  • closed:在某些场景中,开发者可能需要更高程度的封装和安全性,不希望外部代码访问和操作 Shadow DOM。在这种情况下可以选择隔离模式。

👇 当 mode 被设置为 open 时,创建的 Shadow DOM 可以通过 JavaScript 直接访问和操作

// 创建一个影子 DOM
const shadow = this.attachShadow({ mode: 'open' });
console.log(this.shadowRoot); // 访问影子 DOM

👇 当 mode 被设置为 closed 时,样式和模板可以被完全封装,直至需要公开的属性

const shadow = this.attachShadow({ mode: 'closed' });
console.log(this.shadowRoot); // 这将输出 null

3. HTML Templates(HTML 模板)

HTML Templates 允许开发者在页面中定义不会立即渲染的模板内容,这些内容可以在需要时通过 JavaScript 克隆和使用。

模板定义与克隆
  • 模板定义:<template> 元素中定义模板,不显示在文档但可以进行克隆

    <template id="my-template"><p>This is a template.</p>
    </template>
    

    👆 定义了一个 元素,其内容不会直接显示在页面上。

  • 内容克隆: 使用 document.importNode()template.content.cloneNode(true) 方法克隆模板内容,并将其插入到 DOM 中。

    方法 1: 使用 document.importNode()

    <script>const template = document.getElementById('my-template');const clone = document.importNode(template.content, true); // 深度克隆模板内容document.body.appendChild(clone); // 将克隆内容插入到 DOM 中
    </script>
    

    方法 2: 使用 template.content.cloneNode(true)

    <template id="my-template"><style>p { color: blue; }</style><p>This is a template paragraph!</p>
    </template><script>const template = document.getElementById('my-template');const content = template.content.cloneNode(true); // 深度克隆模板内容document.body.appendChild(content); // 将克隆内容插入到 DOM 中
    </script>
    

    👆 两种方法都可以实现模板内容的克隆和插入,cloneNode(true) 是更常用的方式。

  • 注意:

    1. <template> 元素的内容是惰性的:其中的脚本不会执行,图片不会加载,直到被插入到 DOM 中。
    2. cloneNode(true) 的参数true 表示深度克隆,包括所有子节点;false 表示只克隆当前节点。
    3. 样式和脚本的作用域:克隆后的内容会继承当前文档的样式和脚本环境。
在 Web Components 中使用模板
class MyElement extends HTMLElement {constructor() {super();const template = document.getElementById('my-template');const clone = document.importNode(template.content, true);this.attachShadow({ mode: 'open' }).appendChild(clone);}
}customElements.define('my-template-element', MyElement);

👆 将模板内容克隆并插入到 Shadow DOM 中,从而实现了组件的封装和复用。


使用 Slot 支持外部内容插入

通过 slot 元素,Web Components 可以接受外部内容的占位符,将外部内容插入到组件的特定位置,而不必改变组件的内部结构。

<template id="my-slot-template"><div><slot name="content"></slot></div>
</template><my-slot-element><p slot="content">This is slotted content.</p>
</my-slot-element>

在这个例子中,<slot> 元素充当了外部内容的占位符,外部内容通过 slot 属性插入到组件的特定位置。


属性支持与监听

Web Components 支持在自定义元素上定义和使用属性,以便通过 HTML 属性或 JavaScript 动态设置和获取组件的状态。

<!-- 使用自定义元素,并设置初始属性 -->
<my-attribute-element message="Hello, Web Components!"></my-attribute-element>
<button onclick="changeMessage()">更改消息</button><script>class MyElement extends HTMLElement {static get observedAttributes() {return ['message'];}constructor() {super();this.render();}attributeChangedCallback(name, oldValue, newValue) {if (name === 'message') {this.render();}}render() {this.innerHTML = `<p>${this.getAttribute('message') || '默认消息'}</p>`;}}customElements.define('my-attribute-element', MyElement);function changeMessage() {const element = document.querySelector('my-attribute-element');element.setAttribute('message', '属性已更改!');}
</script>

👆 通过 static get observedAttributes() 方法声明了需要观察的属性 message,并在 attributeChangedCallback 中处理属性变化时的逻辑。

自定义事件

在 Web Components 中,自定义事件允许组件与外部世界进行交互。通过使用 JavaScript 的 CustomEvent 接口,可以在自定义元素中创建和派发事件,让其它部分的代码可以监听这些事件并做出响应。

class MyElement extends HTMLElement {constructor() {super();this.addEventListener('click', () => {this.dispatchEvent(new CustomEvent('my-event', { detail: 'Hello from custom event!' }));});}
}customElements.define('my-event-element', MyElement);document.querySelector('my-event-element').addEventListener('my-event', (e) => {console.log(e.detail); // 输出: Hello from custom event!
});

👆 当用户点击自定义元素时,会派发一个自定义事件 my-event,外部代码可以监听并处理这个事件。


生命周期回调

Custom Elements 提供了一套生命周期回调方法,允许开发者在组件的不同生命周期阶段执行特定的代码:

  • connectedCallback:当元素被插入到 DOM 中时调用,适合执行设置默认属性、启动数据获取、设置事件监听器等操作。
  • disconnectedCallback:当元素从 DOM 中移除时调用,适合执行清理工作,例如移除事件监听器、停止定时器等。
  • attributeChangedCallback:当元素的属性增加、被移除或更改时调用。要使用此回调,必须定义 static get observedAttributes() 方法。
  • adoptedCallback:当元素从一个文档被移动到另一个文档时调用,这个情况在一般的 Web 应用中较少发生,常见于与多个文档交互的复杂应用。
class LifeCycleElement extends HTMLElement {static get observedAttributes() {return ['data-value'];}constructor() {super();console.log('Constructor: 元素实例化');this.attachShadow({ mode: 'open' });this.shadowRoot.innerHTML = `<div>Initial Value</div>`;}connectedCallback() {console.log('connectedCallback: 元素插入到 DOM 中');this.shadowRoot.querySelector('div').textContent = 'Connected to the DOM';this.start();}disconnectedCallback() {console.log('disconnectedCallback: 元素从 DOM 中被移除');this.stop();}attributeChangedCallback(name, oldValue, newValue) {console.log(`attributeChangedCallback: 属性 ${name} 发生变化,从 ${oldValue} 变为 ${newValue}`);if (name === 'data-value') {this.shadowRoot.querySelector('div').textContent = `Attribute data-value: ${newValue}`;}}adoptedCallback() {console.log('adoptedCallback: 元素被移动到新的文档');}start() {// 例如:启动一个定时器this.interval = setInterval(() => console.log('Active...'), 1000);}stop() {// 清理工作:停止定时器clearInterval(this.interval);}
}// 注册自定义元素
customElements.define('lifecycle-element', LifeCycleElement);

Web Components 组件库:Lit

Lit 是一个用于构建快速、轻量级 Web Components 的 JavaScript 库,它由 Google 的开发团队创建,旨在简化和加速开发符合 Web Components 标准的组件。Lit 本身并不是一个完整的框架,而是一个工具集,帮助开发者轻松构建、自定义和组合 Web Components。

import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';// 定义和注册一个新的自定义元素
@customElement('my-lit-element')
export class MyLitElement extends LitElement {// 定义 CSS 样式static styles = css`p {color: blue;}`;// 使用装饰器定义属性,并指定类型@property({ type: String })message: string = 'Hello, World!';// 渲染模板render() {return html`<p>${this.message}</p>`;}
}

👆 使用 Lit 创建一个简单的自定义元素。Lit 提供了声明式模板、响应式状态管理和作用域样式等功能,使得开发 Web Components 变得更加简单和高效。


为什么 Web Components 没有流行?

尽管 Web Components 具有跨框架兼容性、原生支持和性能优势,但在实际开发中,Vue 和 React 等框架的组件方案仍然是主流。以下是 Web Components 未能广泛流行的几个原因:

  1. 功能局限:Web Components 的 API 相对简单,缺乏内置的状态管理、路由等高级特性。在大型应用中处理状态和复杂逻辑时,Web Components 显得力不从心。
  2. 生态系统较小:相比 Vue 和 React,Web Components 的生态系统较小,缺乏丰富的工具、库和社区支持。
  3. 开发体验:现代前端框架提供了丰富的开发工具和优化体验,而 Web Components 的开发体验相对较为原始。

Web Components 的应用场景

尽管 Web Components 在主流开发中尚未普及,但在某些场景下,它仍然具有明显的优势:

  1. 跨框架组件库:创建可在多种框架中使用的通用 UI 组件。
  2. 微前端架构:构建可独立部署、技术栈无关的应用模块。
  3. 嵌入式组件:开发可嵌入第三方网站的小部件或组件。
  4. 企业级设计系统:构建统一的、可在不同项目间共享的组件库。
  5. 长期维护的项目:利用标准化技术降低对特定框架的依赖。

结论

Web Components 提供了一种原生、标准化的方式来实现组件的封装和复用,具有跨框架兼容性和性能优势。尽管目前其在生态系统和开发体验上存在一些局限,但在特定场景下,Web Components 仍然是一个非常有价值的技术选择。随着 Web 标准的不断发展和完善,Web Components 有望在未来得到更广泛的应用。

希望能让你更好地理解 Web Components,并在实际开发中灵活运用这一技术。如果你有任何问题或建议,欢迎在评论区留言讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/33078.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

十三、OSG学习笔记-osgDB文件读写

上一章节&#xff1a; 十二、OSG学习笔记-Control-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/146082287?spm1001.2014.3001.5501 一、文件读取原理 ReadNodeFile,读取流程&#xff1a; 二、实现一个简单的读取器 仿造ReaderWriterOSG.CPP原码&#x…

05.基于 TCP 的远程计算器:从协议设计到高并发实现

&#x1f4d6; 目录 &#x1f4cc; 前言&#x1f50d; 需求分析 &#x1f914; 我们需要解决哪些问题&#xff1f; &#x1f3af; 方案设计 &#x1f4a1; 服务器架构 &#x1f680; 什么是协议&#xff1f;为什么要设计协议&#xff1f; &#x1f4cc; 结构化数据的传输问题 …

设计模式学习笔记——命令模式

2025年3月13日&#xff0c;周四下午 相同的保存逻辑在各个组件中重复出现。 且需要修改保存逻辑时&#xff0c;各个组件的保存逻辑都需要进行相应修改。 使用了命令模式把保存逻辑从三个组件中独立出来后&#xff0c;减少了代码冗余。 可以通过“保存命令”来使用保存逻辑&am…

CNN-BiLSTM、BiLSTM、CNN多变量时间序列光伏功率预测Matlab

CNN-BiLSTM、BiLSTM、CNN多变量时间序列光伏功率预测Matlab 目录 CNN-BiLSTM、BiLSTM、CNN多变量时间序列光伏功率预测Matlab预测效果基本介绍程序设计参考资料 预测效果 基本介绍 CNN-BiLSTM、BiLSTM、CNN三模型多变量时序光伏功率预测 (Matlab2020b 多输入单输出) 1.程序已…

机器学习算法——聚类任务

目录 1、K-Means 2、K-medoids 3、K-medians 4、层次聚类 5、DBSCAN 6、OPTICS 7、谱聚类 Spectral Clustering 8、高斯混合模型 GMM 9、模糊C-means FCM 10、Mean Shift 11、BIRCH 12、Affinity Propagation 13、对比总结 14、完整代码 1、K-Means 目标:将数据点分组到K个簇中…

【亲测有用】数据集成平台能力演示(支持国产数据库DaMeng与KingBase)

&#x1f525;&#x1f525; AllData大数据产品是可定义数据中台&#xff0c;以数据平台为底座&#xff0c;以数据中台为桥梁&#xff0c;以机器学习平台为中层框架&#xff0c;以大模型应用为上游产品&#xff0c;提供全链路数字化解决方案。 ✨杭州奥零数据科技官网&#xf…

初阶数据结构(C语言实现)——5.2 二叉树的顺序结构及堆的实现

1.二叉树的顺序结构及实现 1.1 二叉树的顺序结构 普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储&#xff0c;需要注意的是这里的堆和操作系统…

搭建阿里云专有网络VPC

目录 一、概述 二、专有网络vpc 2.1 vpc基本信息 2.2 vpc资源管理 2.3 vpc网段管理 三、交换机 四、NAT网关 4.1 绑定弹性公网IP 4.2 NAT网关信息 4.3 绑定的弹性公网IP 4.4 DNAT 4.5 SNAT 五、弹性公网IP 六、访问控制ACL&#xff08;绑定交换机&#xff09; 6…

Android `%d` 与 `1$%d` 格式化的区别

在 Android 开发中&#xff0c;我们经常需要对字符串进行格式化处理&#xff0c;比如动态填充数字、日期、字符等。 其中&#xff0c;%d 和 1$%d 都是格式化占位符&#xff0c;但它们在使用上有一些不同。 本文将详细解析这两者的区别&#xff0c;并结合 Kotlin 代码示例帮助你…

Spring MVC面试题(一)

1.什么是Spring MVC&#xff1f; 全称为Model View Controller&#xff0c;Spring MVC是Spring的一个模块&#xff0c;基于MVC架构模式的一个框架 2.Spring MVC优点&#xff1f; 1.可用各种视图技术&#xff0c;不仅限于JSP 2.支持各种请求资源映射策略 3. Spring MVC工作原…

AI自动化编程初探

先说vscodeclinemodelscope方案&#xff0c;后面体验trae或者cursor再写写其它的。vscode和trae方案目前来说是免费的&#xff0c;cursor要用claud需要付费&#xff0c;而且不便宜&#xff0c;当然效果可能是最好的。 vscode方案&#xff0c;我的经验是最好在ubuntu上&#xff…

什么是全栈?

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点下班 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 &#x1f4c3;文章前言 &#x1f537;文章均为学习工…

爬虫一些基础知识的备忘录(需要自取)

前言 基础薄弱&#xff0c;或许是ai用多的缘故&#xff0c;记录了写爬虫需要的一些基础知识&#xff0c;需要自取 这里记录一些我初学爬虫的时候经常忘记的东西&#xff0c;包括但不限于一些文件的读写和一些其他的东西 文件读写 文件读写&#xff0c;如果想表达——若文件…

ChromeOS 134 版本更新

ChromeOS 134 版本更新 一、ChromeOS 134 更新内容 1. ChromeOS 自助终端&#xff08;Kiosk&#xff09;模式支持隔离 Web 应用&#xff08;Isolated Web Apps&#xff09; 从 ChromeOS 134 开始&#xff0c;自助终端&#xff08;Kiosk&#xff09;模式支持 隔离 Web 应用&a…

【redis】list类型:基本命令(上)

文章目录 插入和弹出操作获取和删除等操作允许有重复元素LPUSH/RPUSHLRANGELPUSHX/RPUSHXLPOP/RPOPLINDEXLINSERT 插入和弹出操作 列表&#xff08;list&#xff09;相当于数组或者顺序表 约定最左侧元素下标为 0Redis 的下标支持负数下标&#xff08;从后往前数&#xff09;…

Science Advances 视触觉传感机制的交互装置,可以实时测量来自手不同部位的分布力

近日&#xff0c;由香港科技大学&#xff08;HKUST&#xff09;电子与计算机工程学系申亚京教授领导的研究团队&#xff0c;提出了一种基于数字通道的触觉交互系统&#xff0c;可以实时测量来自手不同部位的分布力&#xff0c;有望在医学评估、体育训练、机器人和虚拟现实&…

美食分享平台(源码+数据库+万字文档)

一、项目介绍 440.基于SpringBoot的美食分享平台&#xff0c;系统包含两种角色&#xff1a;管理员、用户,系统分为前台和后台两大模块&#xff0c;主要功能如下。 【前台功能】 1. 首页&#xff1a;提供用户进入系统的入口。 2. 菜谱&#xff1a;用户可以浏览系统中分享的各种…

uniapp简单table表

<template><view class"container"><scroll-view scroll-x"true" scroll-y"true" class"table-scroll"><view class"table-header"><view class"table-cell fixed-column">序号<…

微信小程序:实现多功能表格效果,例如滚动效果、宽度自定义、多选、行内编辑等功能

一、表格效果 1、实现功能 表格实现可横向水平滚动表格、宽度自定义、文本编辑、数字加减、多选&#xff0c;行选中效果&#xff0c;获取选中行数据等功能 2、图片效果 二、代码 1、wxml 根据头循环将表格头进行循环&#xff0c;再通过昂循环展示行内的全部信息&#xff0…

uni-app vue2 记住密码功能

1. html代码 <checkbox-group change"checkboxChange"><label><checkbox value"" :checked"ifSavePwd" style"transform: scale(0.6);"/>记住密码</label> </checkbox-group>2. js代码 默认复选款是不…