如何用Vanilla JS构建可复用Web组件库?含新手入门指南
从零开始用Vanilla JS构建组件库:一步一步来
嗨!作为一个从Vanilla JS摸爬滚打过来的开发者,完全懂你从零开始搭组件库的迷茫——尤其是还要兼顾复用、团队共享这些实际问题。咱们一步一步来,从最基础的开始,保证通俗易懂~
一、先搭好项目基础结构
首先不用搞太复杂的配置,先把项目架子搭起来:
- 新建一个文件夹,比如叫
my-vanilla-components - 里面分几个核心目录:
src/:放所有组件的源码(比如src/components/专门存组件文件)dist/:打包后的成品文件(给别人用的)demo/:用来测试组件的页面(自己调试用)
- 打开终端,进入文件夹,初始化npm(方便后续打包和共享):
npm init -y - 选个简单的打包工具:新手推荐用
esbuild,配置简单速度还快,安装它:npm install esbuild --save-dev
二、写第一个组件:带Loader的按钮
咱们从你说的按钮开始,用原生**自定义元素(Web Components)**来做——这是Vanilla JS做组件库的最佳选择,原生支持样式隔离、可复用,不用依赖任何框架。
1. 编写按钮组件代码
在src/components/Button.js里写如下代码:
class MyButton extends HTMLElement { constructor() { super(); // 开启Shadow DOM:隔离组件样式和结构,不会污染全局 this.attachShadow({ mode: 'open' }); } // 组件挂载到页面时执行的方法,用来渲染内容 connectedCallback() { // 获取HTML标签上的属性,比如loading状态、按钮文本 const isLoading = this.hasAttribute('loading'); const buttonText = this.textContent || '默认按钮'; const buttonColor = this.getAttribute('color') || '#007bff'; // 渲染组件的结构和样式 this.shadowRoot.innerHTML = ` <style> .my-button { padding: 8px 16px; border: none; border-radius: 4px; background: ${buttonColor}; color: white; cursor: pointer; font-size: 14px; transition: opacity 0.2s; } .my-button:disabled { opacity: 0.7; cursor: not-allowed; } .loader { width: 14px; height: 14px; border: 2px solid #fff; border-top: 2px solid transparent; border-radius: 50%; animation: spin 1s linear infinite; display: inline-block; margin-right: 6px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> <button class="my-button" ${isLoading ? 'disabled' : ''}> ${isLoading ? '<span class="loader"></span>' : ''} ${buttonText} </button> `; } // 监听哪些属性变化,这里监听loading static get observedAttributes() { return ['loading']; } // 属性变化时重新渲染组件 attributeChangedCallback(name) { if (name === 'loading') { this.connectedCallback(); } } } // 注册自定义元素,以后就能在HTML里用<my-button>标签了 customElements.define('my-button', MyButton);
2. 测试组件
在demo/index.html里写测试页面:
<!DOCTYPE html> <html> <head> <title>按钮组件测试</title> </head> <body> <h3>普通按钮</h3> <my-button color="#28a745">确认</my-button> <h3>加载中按钮</h3> <my-button loading>正在提交...</my-button> <!-- 引入组件代码 --> <script src="../src/components/Button.js"></script> </body> </html>
直接打开这个HTML文件,就能看到两个按钮的效果啦!点击加载中的按钮会发现是禁用状态,还有旋转的loader。
三、组件复用的核心要点
要让组件真正能复用,记住这几个关键点:
- 样式隔离:一定要用Shadow DOM,不然组件的CSS会和页面其他样式冲突(比如页面里的
.button样式会影响你的组件)。 - 属性驱动:组件的状态用HTML属性控制(比如
loading、color),用户用的时候直接在标签上加属性就行,不用写复杂的JS。 - 封装逻辑:把组件的交互逻辑(比如点击事件、状态切换)封装在类里,外部只需要通过属性或暴露的方法调用。比如要给按钮加点击事件,可以在组件里监听:
外部页面就能监听这个事件:// 在connectedCallback里加 const button = this.shadowRoot.querySelector('.my-button'); button.addEventListener('click', () => { // 可以触发自定义事件,让外部监听 this.dispatchEvent(new CustomEvent('button-click', { detail: '按钮被点击了' })); });document.querySelector('my-button').addEventListener('button-click', (e) => { console.log(e.detail); }); - 可配置性:给组件留一些可自定义的属性(比如颜色、大小),让用户能根据需求调整,不用改你的源码。
四、把库共享给团队
做好组件后,要让团队能用得上,分两步:
1. 打包成可复用的文件
在package.json里加一个打包脚本:
"scripts": { "build": "esbuild src/index.js --bundle --minify --outfile=dist/my-components.js" }
然后创建src/index.js,把所有组件导入(以后加新组件都在这里加):
// 导入按钮组件 import './components/Button.js'; // 以后加的表单、轮播组件都在这里导入
运行打包命令:
npm run build
这样dist/文件夹里就会生成一个my-components.js,这就是团队可以直接用的文件。
2. 共享方式
根据团队情况选一种:
- 私有npm仓库:如果公司有私有npm,直接运行
npm publish --registry=你的私有仓库地址,团队成员用npm install my-vanilla-components就能安装使用。 - Git仓库:把代码推到公司的GitLab/GitHub,团队成员克隆下来后,直接用
dist/里的文件,或者自己运行npm run build生成。 - 直接发文件:小团队可以直接把
my-components.js发给同事,他们在项目里引入就行。
五、在真实页面中使用组件
有三种常用方式:
- 直接引入打包文件:
<!-- 在页面里引入 --> <script src="path/to/my-components.js"></script> <!-- 直接用自定义标签 --> <my-button loading>提交表单</my-button>
- npm安装后导入:
如果是通过npm安装的,在项目的JS文件里导入:
import 'my-vanilla-components';
然后在HTML里用<my-button>标签即可。
3. 动态创建组件:
用JS动态生成组件(适合需要动态渲染的场景):
const button = document.createElement('my-button'); button.textContent = '动态生成的按钮'; button.setAttribute('color', '#dc3545'); document.body.appendChild(button);
六、后续扩展:表单、轮播等组件
有了按钮的基础,后续加其他组件就很顺了:
- 表单组件:比如
my-input,同样用自定义元素,封装输入验证、样式,监听input事件暴露输入值。 - 图片轮播:
my-carousel,封装轮播逻辑,支持自动播放、切换按钮,用autoplay、interval等属性控制。 - 统一主题:可以在
src/styles/global.css里定义主题变量(比如--primary-color: #007bff),每个组件里引入这个文件,保持样式统一。
最后几个小Tips
- 每次写完组件都在
demo/页面测试,确保各种属性和交互都正常。 - 写个简单的README,把每个组件的用法、属性说明写清楚,团队成员一看就懂。
- 不用追求完美,先把核心组件做好,再慢慢迭代优化。
内容的提问来源于stack exchange,提问作者pat__
相关产品推荐
相关产品推荐

