一、需求痛点:设计师的「像素眼」与产品的「五彩斑斓」

  1. 默认的 <Button size="small">编辑</Button> 太「业务系统」;
  2. 图标库风格不统一,Antd 官方图标「圆角 2px」与 UI 规范「线性 1.5px」冲突;
  3. 操作列宽度写死 120px,国际化后按钮换行;
  4. 暗黑模式切换,按钮 hover 色值要同步变量。

目标

  • 保留 Ant Design Table 分页/排序/过滤等能力;
  • 用 Tailwind CSS 原子类任意定制图标按钮样式;
  • 图标可来自 Heroicons/Tabler/自定义 SVG,一键替换;
  • 代码量 ≤ 30 行,TypeScript 友好。

二、技术选型:Antd 负责行为,Tailwind 负责颜值

层级 技术 职责
数据层 React 19 + useMemo 行数据 → 列配置
组件层 Ant Design Table 分页、排序、加载、伸缩
样式层 Tailwind CSS 3.4+ 图标、按钮、hover、dark 模式
图标层 Heroicons(或 iconfont) 1.5px 线性统一规范

Antd 的 render 列渲染函数 = 空白画布,Tailwind 想画啥画啥。


三、30 秒搭骨架:最简操作列

import { Table } from 'antd';
import { PencilIcon, TrashIcon } from '@heroicons/react/24/outline';

const data = [
  { id: 1, name: 'iPhone 15', price: 5999 },
  { id: 2, name: 'MacBook Air', price: 8999 },
];

const columns = [
  { title: '商品', dataIndex: 'name' },
  { title: '价格', dataIndex: 'price', render: v => `¥${v}` },
  {
    title: '操作',
    key: 'action',
    width: 96,                         // 4 个按钮 24px 刚好
    render: (_, record) => (
      <div className="flex items-center gap-2">
        <button
          type="button"
          onClick={() => console.log('edit', record)}
          className="text-gray-500 hover:text-blue-600
                     transition-colors duration-200"
        >
          <PencilIcon className="h-5 w-5" />
        </button>
        <button
          type="button"
          onClick={() => console.log('delete', record)}
          className="text-gray-500 hover:text-red-600
                     transition-colors duration-200"
        >
          <TrashIcon className="h-5 w-5" />
        </button>
      </div>
    ),
  },
];

export default function ProductTable() {
  return <Table rowKey="id" columns={columns} dataSource={data} />;
}
  • <Button>,零 Antd 样式侵入;
  • gap-2 = 8px,Tailwind 栅格系统;
  • 深色模式自动切换:加 dark:text-gray-400 dark:hover:text-blue-400 即可。

四、进阶 1:「更多」下拉菜单 + 权限控制

import { Dropdown } from 'antd';
import { EllipsisVerticalIcon } from '@heroicons/react/24/outline';

const menuItems = (record) => [
  { key: 'edit', label: '编辑', onClick: () => handleEdit(record) },
  { key: 'delete', label: '删除', onClick: () => handleDelete(record) },
];

{
  title: '操作',
  key: 'action',
  width: 64,
  render: (_, record) => (
    <Dropdown menu={{ items: menuItems(record) }} trigger={['click']}>
      <button
        type="button"
        className="text-gray-400 hover:text-gray-700
                   dark:text-gray-500 dark:hover:text-gray-200"
      >
        <EllipsisVerticalIcon className="h-5 w-5" />
      </button>
    </Dropdown>
  ),
}
  • 只暴露一个「⋮」图标,节省横向空间
  • 权限控制:在 menuItems 里直接 filter 掉无权限项。

五、进阶 2:组合按钮 + 文字(国际化)

<div className="flex items-center gap-3">
  <Button
    size="small"
    type="text"
    icon={<PencilIcon className="h-4 w-4" />}
    onClick={() => handleEdit(record)}
  >
    <span className="ml-1 hidden sm:inline">Edit</span>
  </Button>
</div>
  • sm:inline 响应式:手机只显示图标,PC 显示文字;
  • Antd Button type="text" 本身零边框,再叠 Tailwind 不会冲突。

六、进阶 3:Hover 整行高亮操作区

<Table
  rowClassName="group"
  columns={[
    ...,
    {
      title: '操作',
      key: 'action',
      width: 80,
      render: (_, record) => (
        <div className="opacity-0 group-hover:opacity-100
                        transition-opacity duration-200">
          <PencilIcon
            onClick={() => handleEdit(record)}
            className="h-5 w-5 text-gray-400 hover:text-blue-600
                       cursor-pointer"
          />
        </div>
      ),
    },
  ]}
/>
  • group/group-hover 是 Tailwind 官方功能;
  • 减少常驻视觉噪点,设计师点赞

七、深色模式一步到位

/* 无需额外 CSS,Tailwind 已支持 */
.dark .text-gray-500 { color: rgba(255,255,255,0.6); }

htmlclass="dark" 即可,Antd 5 主题算法与 Tailwind 无关,并行不冲突


八、TypeScript 类型提示:给 render 加泛型

import type { ColumnsType } from 'antd/es/table';

interface Product {
  id: number;
  name: string;
  price: number;
}

const columns: ColumnsType<Product> = [
  ...,
  {
    title: '操作',
    key: 'action',
    render: (_, record) => ( ... ),  // record 自动推断为 Product
  },
];

九、性能小贴士

  1. columnsuseMemo 包裹,避免重渲染;
  2. 图标库按需导入,只打包用到的 3 个 SVG
  3. 行内 onClickuseCallback 包一层,减少子组件刷新。

十、总结:一句话记住

Antd 管数据,Tailwind 管颜值;render 是画布,图标随你意。

  • 操作列 = 普通 column + render 返回任意 JSX;
  • Tailwind 原子类零冲突覆盖 Antd 默认样式;
  • 图标用 Heroicons/Iconfont/SVG 均可,样式一致
  • 深色、响应、权限、动画全部原子类搞定,不写一行 less/css
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐