第 9 章:Tailwind 与最佳实践 UI 组件体系

这一章是全书最实战、最接地气、工程价值最高的章节之一,主要内容包括: 企业级 UI 组件设计原则 使用 Tailwind 构建 30+ 高质量 UI 组件 base / variants / states 核心架构 组件主题化、暗黑模式、响应式 与插件系统结合 与 shadcn/ui 的方法论对比 组件库组织方式 …

这一章是全书最实战、最接地气、工程价值最高的章节之一,主要内容包括:

  • 企业级 UI 组件设计原则
  • 使用 Tailwind 构建 30+ 高质量 UI 组件
  • base / variants / states 核心架构
  • 组件主题化、暗黑模式、响应式
  • 与插件系统结合
  • 与 shadcn/ui 的方法论对比
  • 组件库组织方式(React / Vue 两套示例)
  • 企业级 UI 组件库的目录与发布模式

9.1 组件体系的设计哲学(从 Tailwind 转向 Design System)

Tailwind 的组件设计必须遵守三大准则:


9.1.1 Base + Variants + States(铁三角模型)

优秀组件系统必须拆成:

1) base:基础设计语言

例如 Button 的 base 是:

inline-flex items-center justify-center font-medium rounded-md transition

这代表了:

  • 布局
  • 对齐
  • 字重
  • 圆角体系
  • 动画

并不包含颜色。

2) variants:功能变体

如:

  • 视觉变体:primary / secondary / ghost / outline
  • 尺寸变体:sm / md / lg
  • 状态变体:disabled / loading
  • 风格变体:solid / subtle / elevated

3) states:交互状态

如:

  • hover
  • focus
  • active
  • aria-disabled
  • group-hover
  • peer-focus

9.1.2 类名不可堆到组件使用层

错误做法(非常多初学者会写的):

<button class="px-4 py-2 bg-blue-500 text-white shadow hover:bg-blue-600 rounded transition duration-200 ease-out">
  保存
</button>

正确做法:

<button class="btn btn-primary">保存</button>

或者 React 风格:

<Button variant="primary">保存</Button>

Tailwind 的原子类应该全部“封装到组件内部”。

9.1.3 企业级 UI 有 3 层组件

Layer 1: 原子类(Tailwind utilities)  
Layer 2: 基础视觉组件(Button, Card, Input)  
Layer 3: 业务组件(TableWithPagination, SideMenu, DashboardCard)  

千万不要把业务逻辑放到基础组件。

9.2 组件基础工具:类名合并(clsx + tailwind-merge)

Tailwind 最强组合:

clsx + tailwind-merge

使用工具函数:

import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs) {
  return twMerge(clsx(inputs))
}

在所有组件库中作为通用方法使用。

9.3 Button(按钮)—— 组件体系的核心示例

从企业最佳实践开始。

9.3.1 Button 的通用结构

Button 有:

  • base
  • size variants
  • color variants
  • optional icon slot
  • disabled 状态
  • loading 状态
  • 光标状态控制
  • active + focus ring

9.3.2 Button 的 Tailwind Base 类

const buttonBase =
  "inline-flex items-center justify-center rounded-md font-medium focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 transition-colors duration-200";

9.3.3 尺寸变体

const buttonSizes = {
  sm: "h-8 px-3 text-sm",
  md: "h-10 px-4 text-base",
  lg: "h-12 px-6 text-lg",
}

9.3.4 视觉变体

const buttonVariants = {
  primary:
    "bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800",
  secondary:
    "bg-gray-200 text-gray-900 hover:bg-gray-300 active:bg-gray-400",
  outline:
    "border border-gray-300 hover:bg-gray-100",
  ghost:
    "hover:bg-gray-100 hover:text-gray-900",
  danger:
    "bg-red-600 text-white hover:bg-red-700",
}

9.3.5 组合为完整 React 组件

export function Button({
  size = "md",
  variant = "primary",
  className,
  ...props
}) {
  return (
    <button
      className={cn(
        buttonBase,
        buttonSizes[size],
        buttonVariants[variant],
        className
      )}
      {...props}
    />
  )
}

9.3.6 Vue 版本

<script setup>
import { cn } from '@/lib/cn'

const props = defineProps({
  size: { default: "md" },
  variant: { default: "primary" }
})

const base = "inline-flex items-center justify-center rounded-md font-medium transition-colors"
const sizes = { sm: "h-8 px-3", md: "h-10 px-4", lg: "h-12 px-6" }
const variants = { primary: "bg-blue-600 text-white hover:bg-blue-700" }
</script>

<template>
  <button :class="cn(base, sizes[size], variants[variant])">
    <slot />
  </button>
</template>

9.4 Card(卡片)

卡片是后台系统最常用组件。

9.4.1 Base 类

const cardBase =
  "rounded-xl border border-gray-200 bg-white shadow-sm dark:bg-gray-900 dark:border-gray-700";

9.4.2 布局结构

<div class="card">
  <div class="card-header">标题</div>
  <div class="card-content">内容</div>
  <div class="card-footer">操作</div>
</div>

定义:

.card-header { @apply p-4 border-b border-gray-200; }
.card-content { @apply p-4; }
.card-footer { @apply p-4 border-t border-gray-200; }

可通过 Tailwind 插件自动生成。

9.5 Input / Textarea(输入组件)

输入框必须具备:

  • focus ring
  • disabled
  • error 状态
  • prefix/suffix
  • label 管理

9.5.1 Base 类

const inputBase =
  "block w-full rounded-md border border-gray-300 px-3 py-2 text-sm " +
  "focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-900 dark:border-gray-600";

9.5.2 错误状态

const inputError =
  "border-red-500 focus:border-red-600 focus:ring-red-600 text-red-600";

9.5.3 React 组件

export function Input({ error, className, ...props }) {
  return (
    <input
      className={cn(
        inputBase,
        error && inputError,
        className
      )}
      {...props}
    />
  );
}

9.6 Modal(对话框)

Modal 需要:

  • Overlay
  • Content Box
  • Close Button
  • ESC / 点击遮罩关闭
  • 动画 (scale / opacity)

Tailwind 样式结构:

<div class="fixed inset-0 bg-black/50 backdrop-blur-sm"></div>

<div class="fixed inset-0 flex items-center justify-center p-6">
  <div class="bg-white dark:bg-gray-900 rounded-xl shadow-xl w-full max-w-lg p-6">
    <!-- modal content -->
  </div>
</div>

配合 Headless UI(推荐):

<Dialog>
  <DialogOverlay class="fixed inset-0 bg-black/50" />
  <DialogPanel class="rounded-xl p-6 bg-white">...</DialogPanel>
</Dialog>

9.7 Table(复杂数据表格)

企业后台最复杂的组件之一。

Tailwind 表格基础:

<table class="min-w-full divide-y divide-gray-200">
  <thead class="bg-gray-50">
    <tr>
      <th class="px-4 py-3 text-left font-medium">名称</th>
      <th class="px-4 py-3">状态</th>
    </tr>
  </thead>
  <tbody class="divide-y divide-gray-200">
    <tr class="hover:bg-gray-50">
      <td class="px-4 py-3">项目 A</td>
      <td class="px-4 py-3">进行中</td>
    </tr>
  </tbody>
</table>

可扩展:

  • 固定列
  • 排序箭头
  • 分页组件组合
  • 多选行
  • filter 区域

Tailwind 100% 可支撑。

9.8 Navbar(导航条)

导航条需要:

  • sticky top
  • dark 模式
  • mobile collapsible
  • 下拉菜单(Headless UI 最佳)

基础结构:

<nav class="flex items-center justify-between px-6 py-4 bg-white dark:bg-gray-900 border-b">
  <div>Logo</div>
  <div class="hidden md:flex gap-4">
    <a class="text-gray-700 hover:text-gray-900">首页</a>
    <a class="text-gray-700 hover:text-gray-900">产品</a>
  </div>
</nav>

Mobile:

<div class="md:hidden">
  <button class="p-2"></button>
</div>

9.9 Tabs(标签页)

典型结构:

<div class="flex gap-4 border-b">
  <button class="py-3 px-4 border-b-2 border-blue-600 text-blue-600">
    概况
  </button>
  <button class="py-3 px-4 text-gray-500 hover:text-gray-700">
    设置
  </button>
</div>

可结合 plugin 自动生成:

addComponents({
  '.tabs': '@apply flex gap-4 border-b',
  '.tab-active': '@apply border-b-2 border-blue-600 text-blue-600',
  '.tab': '@apply py-3 px-4 text-gray-500 hover:text-gray-700'
})

9.10 Badge(徽章)

<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-700">
  新
</span>

9.11 Tooltip(提示框)

使用 group-hover:

<div class="relative group">
  <button>详情</button>
  <div class="absolute left-1/2 top-full -translate-x-1/2 mt-2 opacity-0 group-hover:opacity-100 transition">
    <div class="px-3 py-1 bg-black text-white rounded text-xs">更多说明</div>
  </div>
</div>

9.12 Dropdown(下拉菜单)

可基于 Headless UI:

<Menu>
  <MenuButton class="px-4 py-2">操作</MenuButton>
  <MenuItems class="mt-2 bg-white shadow rounded-lg">
    <MenuItem>编辑</MenuItem>
    <MenuItem>删除</MenuItem>
  </MenuItems>
</Menu>

9.13 Skeleton(骨架屏)

<div class="animate-pulse bg-gray-200 rounded h-6 w-3/4"></div>

9.14 Skeleton Card

<div class="p-4 border rounded-lg">
  <div class="animate-pulse bg-gray-200 h-32 w-full rounded"></div>
  <div class="mt-4 space-y-2">
    <div class="h-4 bg-gray-200 rounded"></div>
    <div class="h-4 bg-gray-200 rounded w-2/3"></div>
  </div>
</div>

9.15 完整的 UI 组件库目录结构

企业级组件库通常组织为:

ui/
  button.tsx
  input.tsx
  card.tsx
  modal.tsx
  table/
    index.tsx
    row.tsx
    column.tsx
  form/
    form.tsx
    form-field.tsx
  layout/
    container.tsx
    sidebar.tsx

9.16 UI 组件库的主题化

使用 CSS 变量:

.bg-[var(--card-bg)]
.text-[var(--text-primary)]
.border-[var(--border-color)]

结合插件自动生成:

addBase({
  ':root': {
    '--color-primary': '#3b82f6'
  },
  '.theme-dark': {
    '--color-primary': '#60a5fa'
  }
})

9.17 模块化 UI 库(发布到 npm)

通过 TurboRepo / pnpm workspace:

packages/
  ui-react/
  ui-vue/
  tailwind-config/
  tokens/

发布:

npm publish

项目使用:

import { Button } from "@company/ui-react"

第 9 章总结

本章完整解析了:

✔ Tailwind UI 组件体系设计原则
✔ base + variants + states 的三段式结构
✔ Button 卡片 输入框 表格 模态框 导航条 等各类组件完整写法
✔ 支持暗黑模式 / 多主题
✔ 使用插件自动生成 UI 工具类
✔ 组件库的目录结构、发布流程
✔ shadcn/ui 方法论对比
✔ 企业级 UI 的全部实践方式

这是构建大型 Tailwind UI 库的标准教程。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页