9.1 Vue 3 生态 UI 方案对比
| 库 | 设计风格 | 特点 | 适用场景 |
|---|---|---|---|
| Nuxt UI v3 | Tailwind,高度可定制 | Nuxt 官方,Reka UI 无障碍基础 | Nuxt 全栈项目首选 |
| Shadcn-vue | Tailwind,复制粘贴风格 | 拥有代码所有权,无版本锁定 | 需要完全控制组件代码 |
| 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 条件判断。