Web Components:原生组件化开发新趋势
开篇:Web Components 是什么?用来做什么?

你有没有想过,能不能像拼乐高积木一样开发网页?也就是说,把页面上的每一个小部分(比如按钮、导航栏、弹窗等)都封装成一个个“模块”,需要的时候直接使用它们,而不是每次都从头写一遍。
这就是 Web Components 的核心思想。
Web Components 是浏览器原生支持的一套组件化开发方案,它不需要任何框架(如 React 或 Vue),只需要纯 HTML、CSS 和 JavaScript,就能帮你创建可重用的自定义元素。
为什么说它是“新趋势”?
- 不依赖框架:你可以不用学 React 或 Vue,也可以写出结构清晰、复用性强的组件。
- 组件隔离:样式和逻辑是独立的,不会互相干扰。
- 跨项目复用:在多个项目之间共用一套 UI 组件成为可能。
- 现代浏览器原生支持:主流浏览器都已完整支持。
环境准备:轻松搭建开发环境

如果你是前端零基础,那也不用担心,我们只需要一个最简单的编辑器和浏览器就可以开始 Web Components 的学习。
✅ 基本工具清单:
| 工具 | 说明 |
|---|---|
| 文本编辑器 | VSCode(推荐)、Sublime Text、Atom 等 |
| 浏览器 | Chrome(建议使用最新版)或 Edge |
| HTTP Server(后期用) | 用于解决本地加载问题,可以用 Live Server 插件 |
📝 安装步骤:
下载安装 VSCode
- 打开 https://code.visualstudio.com/
- 根据系统下载并安装(Windows/Mac/Linux)
安装 Live Server 插件(可选,但推荐)
- 在 VSCode 中点击左侧插件图标
- 搜索 “Live Server”
- 点击安装
新建项目文件夹
- 打开 VSCode → 文件 → 打开文件夹 → 新建一个文件夹(比如叫
web-components-demo) - 右键文件夹 → “在资源管理器中打开” 创建以下文件:
index.htmlmain.js
- 打开 VSCode → 文件 → 打开文件夹 → 新建一个文件夹(比如叫
启动服务运行页面
- 在 VSCode 中右键
index.html,点击 “Open with Live Server”
- 在 VSCode 中右键
好了,你现在可以开始写代码了!
核心概念:什么是 Custom Elements、Shadow DOM 和 Templates?

Web Components 主要由三部分组成:
- Custom Elements(自定义元素)
- Shadow DOM(影子 DOM)
- Templates(模板)
我们一个个来看。
一、Custom Elements:创建属于你的 HTML 标签
想象一下:你不仅可以使用 <div>、<button>,还可以自己定义一个标签,比如 <my-card>,就像这样使用:
<my-card>
<h1>欢迎来到我的网站</h1>
<p>这是我的卡片内容</p>
</my-card>
✨ 这就是 Custom Elements 的能力!
实现方法:
你需要通过 JavaScript 定义一个新的 HTML 元素类,并注册它。
// main.js
class MyCard extends HTMLElement {
constructor() {
super();
this.innerHTML = `
<h1>我是自定义卡片</h1>
<p>这是一个简单示例</p>
`;
}
}
customElements.define('my-card', MyCard);
然后,在 index.html 中调用它:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Web Components 初体验</title>
</head>
<body>
<my-card></my-card>
<script type="module" src="main.js"></script>
</body>
</html>
📌 小提示:
自定义标签必须包含一个短横线 -,比如 my-button、user-profile,这是规范要求的。
二、Shadow DOM:隔离组件的样式与结构
如果你现在为 <my-card> 写 CSS,可能会不小心影响到整个页面的样式。这时候就需要 Shadow DOM 来帮助你“包裹”组件的内容,使其不受外界影响,也不会对外造成污染。
怎么做呢?
修改之前的 MyCard 类,加入 shadowRoot:
class MyCard extends HTMLElement {
constructor() {
super();
// 创建 shadow root
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
<style>
h1 {
color: blue;
background: #f0f0f0;
padding: 10px;
}
</style>
<h1>我是自定义卡片</h1>
<p>这是一个带样式的例子</p>
`;
}
}
✅ 效果:h1 只会在 my-card 内部生效,不影响外部样式!
📌 Shadow DOM 有两种模式:
open:可以通过 JS 获取(常用)closed:不可通过 JS 外部访问(通常用于封装更强)
三、Template:预先定义组件结构
上面的代码虽然实现了效果,但直接拼字符串并不方便,容易出错。
我们可以使用 HTML 的 <template> 标签来提前定义结构。
修改后的完整示例:
<!-- index.html -->
<template id="card-template">
<style>
h1 {
color: green;
}
</style>
<h1>卡片标题</h1>
<p>这里是描述文字。</p>
</template>
<script type="module" src="main.js"></script>
// main.js
class MyCard extends HTMLElement {
constructor() {
super();
const template = document.getElementById('card-template');
const content = template.content.cloneNode(true); // 深度复制模板内容
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(content);
}
}
customElements.define('my-card', MyCard);
✅ 这样更清晰地分离了结构、逻辑与样式。
实战项目:做一个带交互的自定义按钮组件

让我们一起动手,做一个实用的小组件 —— 一个带计数功能的按钮。每次点击按钮,会显示点了多少次。
第一步:HTML 结构
<!-- index.html -->
<template id="counter-button-template">
<button class="counter-btn">点击我(0次)</button>
</template>
第二步:JS 逻辑处理
// main.js
class CounterButton extends HTMLElement {
constructor() {
super();
const template = document.getElementById('counter-button-template').content;
const clone = template.cloneNode(true);
this.shadowRoot = this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(clone);
this.button = this.shadowRoot.querySelector('.counter-btn');
this.count = 0;
this.button.addEventListener('click', () => {
this.count++;
this.button.textContent = `点击我(${this.count}次)`;
});
}
}
customElements.define('counter-button', CounterButton);
第三步:在页面中使用它
<counter-button></counter-button>
<counter-button></counter-button>
每个按钮都会有自己的点击计数,互不干扰!
常见问题解答(FAQ)
作为一个初学者,你在开发过程中可能会遇到这些问题。来看看官方答案:
❓ Q1:为什么我刷新页面看不到组件?
可能原因:
- 没正确引入脚本:请确认
main.js是否在页面中被引用 - 路径错误:检查
<script>的src路径是否正确 - 浏览器缓存问题:尝试硬刷新(Chrome 按 Ctrl+F5)
- 没用服务器打开:某些功能不能直接通过
file:///加载,请使用 Live Server 启动页面
❓ Q2:为什么组件样式失效?
- 如果你是通过
innerHTML插入样式,可能被浏览器阻止执行 - 推荐使用
<template>+shadowRoot.innerHTML或<style>注入的方式
❓ Q3:怎么给组件加属性传递数据?
比如你想让卡片显示不同的标题怎么办?
可以通过读取组件上的属性实现:
<my-card title="首页介绍"></my-card>
对应 JS:
class MyCard extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const title = this.getAttribute('title') || '默认标题';
shadowRoot.innerHTML = `
<h2>${title}</h2>
<p>这是内容区域</p>
`;
}
}
学习建议:下一步该学什么?
掌握 Web Components 的基础之后,你已经可以制作基本的组件了。接下来的学习路线如下:
📘 学习进阶知识:
- 使用
observedAttributes()和attributeChangedCallback()监听属性变化 - 动态渲染复杂结构(比如根据参数生成不同布局)
- 用 Webpack 打包组件库(适合发布 npm 包)
📚 推荐阅读资料:
- MDN Web Docs - Web Components
- LitElement / Lit:Google 推出的一个轻量级 Web Component 库,提高开发效率
🔍 实践建议:
- 把你常用的组件封装成 Web Components
- 构建自己的 UI 组件库(按钮、输入框、对话框等)
- 在多个项目之间复用这些组件
总结
本教程带你了解了:
- 什么是 Web Components?
- 如何搭建开发环境
- 自定义元素、Shadow DOM、模板的使用
- 实战完成了一个带交互的组件
- 常见问题及解决方案
- 下一步学习方向
如果你是前端小白,这套技术完全可以作为你入门的第一课 —— 不需要框架也能写出优雅、整洁的代码!
继续努力,你离成为一名真正的开发者又近了一步!🎉
如果你想获取本项目的完整代码,请告诉我,我可以为你打包一份 starter 示例哦!

评论 0