You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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发给同事,他们在项目里引入就行。

五、在真实页面中使用组件

有三种常用方式:

  1. 直接引入打包文件:
<!-- 在页面里引入 -->
<script src="path/to/my-components.js"></script>

<!-- 直接用自定义标签 -->
<my-button loading>提交表单</my-button>
  1. 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__

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 07:52:48