再写一个 React 版本的前端最常用 10 个组件封装,不带虚的,直接上代码 + 暴躁讲解!


🧠 一、为什么你要封装组件?

因为你不是写一次性页面的程序员!
你写的项目要维护、要复用、要团队协作,别每次都要从头写一遍 buttoninput

封装的目的就是:

  • ✅ 提高复用率
  • ✅ 统一风格和逻辑
  • ✅ 降低耦合度
  • ✅ 装逼加分

📦 二、最常用的 React 组件清单(真实业务高频使用)

序号 组件名称 使用场景
1 BaseButton.js 所有按钮统一风格
2 BaseInput.js 表单输入框封装
3 BaseSelect.js 下拉选择器
4 BaseTable.js 数据表格展示
5 BaseModal.js 弹窗通用组件
6 BaseForm.js 表单统一布局与校验
7 BasePagination.js 分页组件
8 BaseBreadcrumb.js 面包屑导航
9 BaseCard.js 内容区块容器
10 BaseSkeleton.js 页面骨架屏

🔥 三、每个组件都来一波暴躁封装(React 函数组件 + Hooks)


1. ✅ BaseButton.js(统一按钮样式 & loading)

// BaseButton.jsx
import React from 'react';
import './BaseButton.css';

function BaseButton({ text, type = 'default', loading, disabled, onClick }) {
  const className = `base-button ${type ? 'base-button--' + type : ''}`;

  return (
    <button className={className} onClick={onClick} disabled={loading || disabled}>
      {loading ? '加载中...' : text}
    </button>
  );
}

export default BaseButton;
/* BaseButton.css */
.base-button {
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
}
.base-button--primary {
  background-color: #409EFF;
  color: white;
}
.base-button--danger {
  background-color: #f56c6c;
  color: white;
}

💬 老子一句话:按钮你要是每次都写 v-loading,你是想累死吗?React 可没有 v-loading,靠你自己封装!


2. ✅ BaseInput.js(表单输入统一处理)

// BaseInput.jsx
import React from 'react';
import './BaseInput.css';

function BaseInput({ label, placeholder, value, onChange, type = 'text' }) {
  return (
    <div className="base-input">
      {label && <label>{label}</label>}
      <input
        type={type}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
      />
    </div>
  );
}

export default BaseInput;
/* BaseInput.css */
.base-input input {
  width: 100%;
  padding: 8px;
  margin-top: 4px;
}

💬 老子一句话:输入框你不封装,你是想让表单变成屎山吗?


3. ✅ BaseSelect.js(下拉选择器统一)

// BaseSelect.jsx
import React from 'react';

function BaseSelect({ value, options, onChange }) {
  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      {options.map((option) => (
        <option key={option.value} value={option.value}>
          {option.label}
        </option>
      ))}
    </select>
  );
}

export default BaseSelect;

💬 老子一句话:选个值你都写不好,你是想气死产品经理吗?


4. ✅ BaseTable.js(数据表格统一结构)

// BaseTable.jsx
import React from 'react';
import './BaseTable.css';

function BaseTable({ data, columns }) {
  return (
    <table className="base-table">
      <thead>
        <tr>
          {columns.map((col, index) => (
            <th key={index}>{col.label}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {data.map((row, i) => (
          <tr key={i}>
            {columns.map((col, j) => (
              <td key={j}>
                {col.render ? col.render(row) : row[col.prop]}
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

export default BaseTable;
/* BaseTable.css */
.base-table {
  width: 100%;
  border-collapse: collapse;
}
.base-table th,
.base-table td {
  border: 1px solid #ddd;
  padding: 8px;
  text-align: left;
}

💬 老子一句话:表格你要是每次都重写 <tr>,你是真不怕重复劳动。


5. ✅ BaseModal.js(弹窗通用组件)

// BaseModal.jsx
import React from 'react';
import './BaseModal.css';

function BaseModal({ visible, title, onClose, children }) {
  if (!visible) return null;

  return (
    <div className="base-modal">
      <div className="modal-mask" onClick={onClose}></div>
      <div className="modal-content">
        <h3>{title}</h3>
        <button className="close-btn" onClick={onClose}>X</button>
        <div className="modal-body">{children}</div>
        <div className="modal-footer">
          <button onClick={onClose}>取消</button>
          <button onClick={() => alert('提交')}>确定</button>
        </div>
      </div>
    </div>
  );
}

export default BaseModal;
/* BaseModal.css */
.base-modal .modal-mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
}
.modal-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
  z-index: 100;
}
.close-btn {
  float: right;
  margin-top: -20px;
}

💬 老子一句话:弹窗你不封装,你是想让页面炸了?


6. ✅ BaseForm.js(表单统一结构)

// BaseForm.jsx
import React from 'react';

function BaseForm({ onSubmit, onCancel, children }) {
  return (
    <form onSubmit={onSubmit} className="base-form">
      {children}
      <div className="form-actions">
        <button type="submit">提交</button>
        <button type="button" onClick={onCancel}>取消</button>
      </div>
    </form>
  );
}

export default BaseForm;

💬 老子一句话:表单你不统一结构,你是想让你的代码像厕所一样乱?


7. ✅ BasePagination.js(分页组件)

// BasePagination.jsx
import React from 'react';

function BasePagination({ currentPage, totalPages, onPageChange }) {
  function prev() {
    if (currentPage > 1) onPageChange(currentPage - 1);
  }

  function next() {
    if (currentPage < totalPages) onPageChange(currentPage + 1);
  }

  return (
    <div className="base-pagination">
      <button onClick={prev} disabled={currentPage === 1}>
        上一页
      </button>
      <span>{currentPage}/{totalPages}</span>
      <button onClick={next} disabled={currentPage >= totalPages}>
        下一页
      </button>
    </div>
  );
}

export default BasePagination;

💬 老子一句话:分页你不封装,你是想把产品经理干哭吗?


8. ✅ BaseBreadcrumb.js(面包屑导航)

// BaseBreadcrumb.jsx
import React from 'react';

function BaseBreadcrumb({ items }) {
  return (
    <div className="base-breadcrumb">
      {items.map((item, index) => (
        <span key={index}>
          {item}
          {index !== items.length - 1 && ' / '}
        </span>
      ))}
    </div>
  );
}

export default BaseBreadcrumb;

💬 老子一句话:没有面包屑的系统,就像没有地图的迷宫。


9. ✅ BaseCard.js(内容卡片)

// BaseCard.jsx
import React from 'react';

function BaseCard({ title, children }) {
  return (
    <div className="base-card">
      {title && <h3>{title}</h3>}
      <div className="card-content">{children}</div>
    </div>
  );
}

export default BaseCard;

💬 老子一句话:内容区域不封装成 Card,你是想让 UI 看着难受吗?


10. ✅ BaseSkeleton.js(骨架屏)

// BaseSkeleton.jsx
import React from 'react';
import './BaseSkeleton.css';

function BaseSkeleton({ rows = 5 }) {
  return (
    <div className="base-skeleton">
      {Array.from({ length: rows }).map((_, i) => (
        <div key={i} className="skeleton-row"></div>
      ))}
    </div>
  );
}

export default BaseSkeleton;
/* BaseSkeleton.css */
.base-skeleton {
  padding: 16px;
}
.skeleton-row {
  height: 20px;
  background: #eee;
  margin: 10px 0;
  animation: pulse 1.5s infinite ease-in-out;
}

@keyframes pulse {
  0% { opacity: 0.4; }
  50% { opacity: 1; }
  100% { opacity: 0.4; }
}

💬 老子一句话:数据没回来前你不给用户看点东西,用户以为你网站挂了。


🧰 四、如何组织这些组件?(老子教你目录结构)

src/
├── components/
│   ├── BaseButton.jsx
│   ├── BaseInput.jsx
│   ├── BaseSelect.jsx
│   ├── BaseTable.jsx
│   ├── BaseModal.jsx
│   ├── BaseForm.jsx
│   ├── BasePagination.jsx
│   ├── BaseBreadcrumb.jsx
│   ├── BaseCard.jsx
│   └── BaseSkeleton.jsx
└── App.jsx

💬 老子一句话:组件不归类,你是想让新人翻文件翻到吐血吗?


🎁 五、老子送你一个自动注册全局组件的方法(React 不支持 Vue 那种 use,但你可以这样搞)

虽然 React 没有 Vue 的 use(),但你可以:

// components/index.js
export { default as BaseButton } from './BaseButton';
export { default as BaseInput } from './BaseInput';
export { default as BaseSelect } from './BaseSelect';
export { default as BaseTable } from './BaseTable';
export { default as BaseModal } from './BaseModal';
export { default as BaseForm } from './BaseForm';
export { default as BasePagination } from './BasePagination';
export { default as BaseBreadcrumb } from './BaseBreadcrumb';
export { default as BaseCard } from './BaseCard';
export { default as BaseSkeleton } from './BaseSkeleton';

然后在你的页面里可以这样引入:

import {
  BaseButton,
  BaseInput,
  BaseTable,
  BasePagination
} from '@/components';

🧠 六、老子总结一句话:

这 10 个组件你要是不会封装,你就别写前端了。


😎💥

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐