Web Components:原生组件化开发新趋势(初学者教程)
本文适合完全零基础的前端学习者,用最简单的语言讲解Web Components,并手把手带你从0开始实践一个项目。
🌟 开篇:什么是 Web Components?能做什么?

你可能听说过 React、Vue、Angular 这些前端框架。它们都有一个共同点:都使用了“组件”的思想来组织代码。
那有没有一种方式,可以在不依赖任何框架的前提下,也能实现“组件”的效果呢?有!就是我们要讲的 —— Web Components(网页组件)。
简单理解:
- Web Components 是浏览器原生支持的一套标准。
- 它允许我们自定义 HTML 标签,例如
<my-button>、<user-card>。 - 每个组件可以独立封装结构(HTML)、样式(CSS)、行为(JavaScript),做到“写一次,到处用”。
使用场景举例:
- 构建可复用的 UI 组件库
- 在多个项目中共享按钮、表单等模块
- 与任意技术栈(React、Vue、jQuery)结合使用
- 提升团队协作效率
🧰 环筑:开发环境搭建

Web Components 是原生 JavaScript 的一部分,不需要安装复杂的工具,但为了更好的体验和调试,我们建议这样准备:
✅ 基础要求:
- 一台电脑
- 浏览器(推荐 Chrome / Edge)
- 编辑器(推荐 VSCode)
💻 步骤一:新建文件夹和文件
- 打开文件管理器,在桌面或某个地方创建一个文件夹,比如叫
web-components-tutorial - 打开这个文件夹,新建以下三个文件:
index.html(主页面)main.js(主要逻辑)styles.css(样式文件)
📂 文件结构如下:
web-components-tutorial/
├── index.html
├── main.js
└── styles.css
🔍 测试是否成功:
在 index.html 中输入以下内容:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>Web Components 教程</title>
</head>
<body>
<h1>Hello Web Components!</h1>
<script type="module" src="./main.js"></script>
</body>
</html>
然后打开浏览器,直接拖动 index.html 到浏览器窗口,看到 “Hello Web Components!” 就说明环境搭好了 ✅
🧠 核心概念讲解
Web Components 由三个核心技术组成:
| 技术名称 | 功能简述 |
|---|---|
| 自定义元素(Custom Elements) | 创建自己的 HTML 标签 |
| Shadow DOM | 让组件有自己的“私有空间”,样式不会冲突 |
| HTML 模板(Template & Slot) | 预定义一段 HTML 结构,供组件重复使用 |
接下来我们逐个介绍这些概念,并用代码例子帮你理解和掌握。
1️⃣ 自定义元素(Custom Element)
这是 Web Components 最核心的功能 —— 自定义标签
示例:做一个 <hello-world> 标签
步骤如下:
- 在
main.js中编写如下代码:
class HelloWorld extends HTMLElement {
constructor() {
super(); // 必须调用,否则报错
this.innerHTML = "你好,我是一个自定义组件 👋";
}
}
// 注册该组件为 <hello-world>
customElements.define('hello-world', HelloWorld);
- 修改
index.html中 body 内容为:
<hello-world></hello-world>
保存后刷新页面,你会看到这句话:
你好,我是一个自定义组件 👋
✅ 成功创建了一个自定义元素!
2️⃣ Shadow DOM:让组件的样式“私有”
问题来了:如果我们给组件加 CSS 样式,会不会影响到其他部分?
答案是:如果不用 Shadow DOM,会;如果用了,就不会。
Shadow DOM 就像一个“小宇宙” —— 里面的样式只作用于组件本身,外界看不到。
示例:让 hello-world 变得更美观
修改 main.js 中的内容:
class HelloWorld extends HTMLElement {
constructor() {
super();
// 创建 shadow DOM
const shadow = this.attachShadow({ mode: 'open' });
// 创建一个 span 元素
const text = document.createElement('span');
text.textContent = '你好,组件中的文字 🎨';
text.style.color = 'red';
// 把 span 添加到 shadow dom
shadow.appendChild(text);
}
}
customElements.define('hello-world', HelloWorld);
现在刷新页面,你会发现字体变成了红色,并且无法通过外部样式去覆盖它。
这就是 Shadow DOM 的保护能力!
3️⃣ Template 和 Slot:灵活布局你的组件
有时候我们需要预设一组结构,而不是每次手动拼接字符串。这时就可以使用 HTML 的 <template> 标签。
而 slot 元素可以让你把内容“插入”到模板的不同位置。
示例:带插槽的组件
- 在
index.html中添加一个<template>:
<template id="card-template">
<style>
.card {
border: 1px solid #ddd;
padding: 1rem;
margin: 1rem;
max-width: 300px;
}
h2 {
color: #444;
}
</style>
<div class="card">
<h2><slot name="title">默认标题</slot></h2>
<p><slot name="content">默认内容</slot></p>
</div>
</template>
- 修改
main.js来使用这个模板:
class MyCard extends HTMLElement {
constructor() {
super();
const template = document.getElementById('card-template');
const shadow = this.attachShadow({ mode: 'open' });
shadow.appendChild(template.content.cloneNode(true));
}
}
customElements.define('my-card', MyCard);
- 在
index.html中使用它:
<my-card>
<span slot="title">这是一个标题</span>
<span slot="content">这是卡片内容区域。</span>
</my-card>
结果就是展示一个带样式的卡片,而且你可以随意传入内容!
🛠 实战项目:做个“用户信息卡片”组件
我们来一起完成一个小项目:制作一个可复用的 <user-card> 组件,用来展示用户信息。
🎯 功能目标:
- 显示头像、姓名、简介
- 可以自定义图片链接和内容
- 使用 Shadow DOM 和模板
第一步:定义模板结构
在 index.html 添加一个 <template>:
<template id="user-card-template">
<style>
.container {
display: flex;
align-items: center;
gap: 1rem;
border: 1px solid #eee;
padding: 1rem;
border-radius: 6px;
width: 350px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
img {
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 50%;
}
h3 {
margin: 0;
}
</style>
<div class="container">
<img src="" alt="avatar" />
<div>
<h3><slot name="name">匿名用户</slot></h3>
<p><slot name="bio">暂无介绍</slot></p>
</div>
</div>
</template>
第二步:创建组件类
在 main.js 中替换为以下代码:
class UserCard extends HTMLElement {
constructor() {
super();
const template = document.getElementById('user-card-template');
const shadow = this.attachShadow({ mode: 'open' });
shadow.appendChild(template.content.cloneNode(true));
}
}
customElements.define('user-card', UserCard);
第三步:在页面中使用组件
还是在 index.html 中,添加以下内容:
<user-card>
<img slot="avatar" src="https://picsum.photos/id/237/200/300" />
<span slot="name">张小明</span>
<span slot="bio">热爱编程,喜欢写博客 😊</span>
</user-card>
⚠️ 但是目前 <img slot="avatar"> 不会被渲染,因为我们在模板里没有预留 slot 叫做 avatar。
让我们修改模板中 <img> 的部分:
<!-- 修改后的 img 标签 -->
<img src="default.jpg" alt="avatar" /><slot name="avatar"></slot>
或者换一种方式:通过属性传递图片地址。
我们可以升级组件:
✅ 升级版:通过属性传参控制图片
修改 UserCard 类如下:
class UserCard extends HTMLElement {
constructor() {
super();
const template = document.getElementById('user-card-template');
const shadow = this.attachShadow({ mode: 'open' });
shadow.appendChild(template.content.cloneNode(true));
// 获取属性值
const avatar = this.getAttribute('avatar') || 'https://picsum.photos/id/237/60/60';
const name = this.getAttribute('name') || '匿名用户';
const bio = this.getAttribute('bio') || '暂无介绍';
// 设置真实值
shadow.querySelector('img').src = avatar;
shadow.querySelector('h3').textContent = name;
shadow.querySelector('p').textContent = bio;
}
}
这时候就可以这样使用:
<user-card
avatar="https://picsum.photos/id/237/60/60"
name="李小龙"
bio="中国功夫传奇人物 🥋">
</user-card>
这样就可以动态展示不同的用户信息啦!
❓ 常见问题解答
Q1:Web Components 和 Vue/React 有什么区别?
A:Web Components 是浏览器原生支持的技术,不依赖任何框架,适合构建通用组件库。而 Vue/React 是第三方框架,功能更多但也需要引入额外依赖。
Q2:组件样式怎么生效?
A:要确保样式写在 Shadow DOM 或 Template 中,或者使用全局 CSS。注意 Shadow DOM 会隔离样式。
Q3:为什么 <img slot="avatar"> 没显示?
A:这是因为你在模板中没有对应的 <slot name="avatar">,请检查模板结构,或者改为通过属性传入图片地址。
Q4:如何调试 Web Components?
A:使用 Chrome 开发者工具,查看 “Shadow DOM” 是否正确挂载,样式是否被应用。
🚀 学习建议:下一步该学什么?
恭喜你完成了第一个 Web Components 项目!接下来的学习路径建议如下:
推荐继续学习:
深入了解 Shadow DOM
- 更高级的样式控制技巧
- 使用
part关键字暴露部分样式给外部重写
结合 Webpack/Vite 打包工具
- 实现组件的模块化导出和复用
- 构建完整的组件库
研究 LitElement / FAST / Open WC 等库
- 这些基于 Web Components 构建的现代库提升了开发效率和功能
尝试封装复杂组件
- 如表格、菜单、对话框等
- 加入事件处理、数据绑定、动画等交互效果
🎁 结语
Web Components 是未来前端组件化的底层支撑技术,学习它不仅能帮助你写出更加模块化、可维护的代码,还能提升你对前端本质的理解。
如果你以前觉得组件只能靠框架来做,那你一定要试试原生的方式,也许会打开新的大门!
❤️ 如果你喜欢这篇文章,请点赞分享,也欢迎留言告诉我你想看哪方面的进阶内容~
🎯 文章总字数约:3500 字
📦 下一步资源推荐:MDN Web Components 官方文档

评论 0