Chapter 09

UI 组件库:Nuxt UI / Shadcn-vue

选择合适的 UI 方案,掌握 Tailwind CSS 集成、主题定制和暗色模式的完整实现路径

9.1 Vue 3 生态 UI 方案对比

设计风格特点适用场景
Nuxt UI v3Tailwind,高度可定制Nuxt 官方,Reka UI 无障碍基础Nuxt 全栈项目首选
Shadcn-vueTailwind,复制粘贴风格拥有代码所有权,无版本锁定需要完全控制组件代码
Element Plus传统企业风格功能完整,中文文档后台管理系统
Naive UI现代简洁完整 TypeScript,主题可配中型项目
PrimeVue多主题可选组件丰富,企业级数据密集应用
Headless UI无样式纯逻辑,完全自定义样式需要完全自定义 UI 的项目

9.2 Nuxt UI v3 完整集成

npm install @nuxt/ui
export default defineNuxtConfig({
  modules: ['@nuxt/ui'],
  // Nuxt UI 会自动配置 Tailwind CSS 和 ColorMode
})

常用组件使用

<template>
  <!-- 按钮 -->
  <UButton color="primary" variant="solid" icon="i-heroicons-plus">
    新建项目
  </UButton>

  <!-- 表单输入 -->
  <UForm :schema="schema" :state="formState" @submit="onSubmit">
    <UFormField label="用户名" name="username">
      <UInput v-model="formState.username" placeholder="请输入用户名" />
    </UFormField>
    <UButton type="submit">提交</UButton>
  </UForm>

  <!-- 模态框 -->
  <UModal v-model:open="isOpen">
    <template #content>
      <UCard>
        <template #header>确认操作</template>
        <p>确定要删除吗?</p>
        <template #footer>
          <UButton @click="isOpen = false">取消</UButton>
          <UButton color="red" @click="confirmDelete">删除</UButton>
        </template>
      </UCard>
    </template>
  </UModal>

  <!-- 数据表格 -->
  <UTable :data="rows" :columns="columns">
    <template #actions-cell="{ row }">
      <UButton size="xs" @click="edit(row)">编辑</UButton>
    </template>
  </UTable>
</template>

9.3 主题定制

export default defineAppConfig({
  ui: {
    // 全局颜色主题(使用 Tailwind 颜色)
    colors: {
      primary: 'green',     // 主色:绿色
      secondary: 'teal',   // 副色:青色
      neutral: 'zinc'      // 中性色
    },
    // 组件级别覆盖
    button: {
      defaultVariants: {
        color: 'primary',
        variant: 'solid',
        size: 'md'
      }
    },
    card: {
      slots: {
        root: 'rounded-xl shadow-sm border border-green-100'
      }
    }
  }
})

9.4 Shadcn-vue:拥有代码所有权的 UI

Shadcn-vue 是 shadcn/ui 的 Vue 版本。不同于传统 UI 库,它将组件代码直接复制到你的项目中,你完全拥有代码,可以随意修改。

# 初始化(会创建 components/ui/ 目录和 tailwind 配置)
npx shadcn-vue@latest init

# 按需添加组件(代码会复制到 src/components/ui/)
npx shadcn-vue@latest add button
npx shadcn-vue@latest add dialog
npx shadcn-vue@latest add form
npx shadcn-vue@latest add table
<script setup lang="ts">
import { Button } from '@/components/ui/button'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Input } from '@/components/ui/input'

const open = ref(false)
</script>

<template>
  <Button variant="default" @click="open = true">打开对话框</Button>

  <Dialog v-model:open="open">
    <DialogContent>
      <DialogHeader>
        <DialogTitle>编辑信息</DialogTitle>
      </DialogHeader>
      <Input placeholder="输入内容" />
      <Button @click="open = false">保存</Button>
    </DialogContent>
  </Dialog>
</template>

9.5 Tailwind CSS 集成

# 在 Nuxt 3 中安装(通过模块方式)
npm install --save-dev @nuxtjs/tailwindcss
export default defineNuxtConfig({
  modules: ['@nuxtjs/tailwindcss']
})
import type { Config } from 'tailwindcss'

export default {
  content: [],   // Nuxt 模块自动配置 content
  theme: {
    extend: {
      colors: {
        brand: {
          50:  '#f0fdf4',
          500: '#22c55e',
          900: '#14532d',
        }
      },
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif']
      }
    }
  },
  plugins: [
    require('@tailwindcss/typography'),   // prose 样式
    require('@tailwindcss/forms'),         // 表单样式重置
  ]
} satisfies Config

9.6 暗色模式实现

Nuxt UI 内置了 @nuxtjs/color-mode,实现暗色模式切换极为简单:

<script setup>
const colorMode = useColorMode()

function toggleDark() {
  colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
}
</script>

<template>
  <button @click="toggleDark">
    <span v-if="colorMode.value === 'dark'">☀️ 亮色</span>
    <span v-else>🌙 暗色</span>
  </button>
</template>
/* 使用 dark: 前缀 */
.card {
  @apply bg-white text-gray-900;
  @apply dark:bg-gray-900 dark:text-gray-100;
}
export default defineNuxtConfig({
  colorMode: {
    classSuffix: '',        // 使用 class="dark"(Tailwind 默认)
    preference: 'system',   // 默认跟随系统
    fallback: 'light'        // SSR 回退值
  }
})
选择 UI 库的建议

对于 Nuxt 项目:Nuxt UI v3 是最无缝的选择,完整集成 Nuxt 生态。对于需要完全定制化的项目:Shadcn-vue + Tailwind 是最灵活的方案,你拥有代码所有权。对于传统企业后台:Element Plus 组件更完整,中文文档更友好。不推荐在同一项目中混用多个 UI 库。

Headless UI
无样式 UI 库,只提供可访问性逻辑(ARIA、键盘导航),样式完全由开发者编写。Radix UI、Reka UI 是典型代表,Nuxt UI v3 基于 Reka UI 构建。
CVA(class-variance-authority)
用于管理 Tailwind 条件类名的工具,Shadcn-vue 使用它来处理组件的 variant(如 primary/secondary/destructive)。
CSS 变量主题
Shadcn-vue 使用 CSS 变量(--background、--foreground 等)定义颜色,暗色模式通过 .dark 类切换 CSS 变量值实现,无需 JS 条件判断。