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 回退值
}
})
9.7 无障碍(Accessibility)最佳实践
现代 UI 库(特别是基于 Reka UI 的 Nuxt UI v3)内置了完整的 ARIA 支持和键盘导航。理解无障碍原则有助于选择和使用正确的组件。
<template>
<!-- Nuxt UI 的 UButton 自动处理 role、aria-disabled -->
<UButton
:loading="pending"
aria-label="提交表单"
type="submit"
>
提交
</UButton>
<!-- UForm 自动关联 label 和 input 的 aria-describedby -->
<UFormField label="邮箱地址" name="email" help="我们不会分享你的邮箱">
<UInput v-model="email" type="email" autocomplete="email" />
</UFormField>
</template>
对于 Nuxt 项目:Nuxt UI v3 是最无缝的选择,完整集成 Nuxt 生态。对于需要完全定制化的项目:Shadcn-vue + Tailwind 是最灵活的方案,你拥有代码所有权。对于传统企业后台:Element Plus 组件更完整,中文文档更友好。不推荐在同一项目中混用多个 UI 库。
Nuxt UI 和 Shadcn-vue 的大多数组件(按钮、输入框、模态框)都需要在客户端运行(事件处理、动画)。如果你的页面文件是纯服务端渲染(无 'use client' 或无 ref()),使用这些组件时 Nuxt 会自动处理客户端激活(hydration)。但若 UI 库组件内部使用了浏览器 API(如 window.matchMedia 用于暗色模式检测),需用 <ClientOnly> 包裹,避免 SSR 水合错误。
Vue 3 生态有丰富的 UI 方案,各有适用场景:Nuxt UI v3 基于 Reka UI(Headless),提供完整无障碍支持,与 Nuxt 深度集成,是 Nuxt 项目的首选;Shadcn-vue 拥有代码所有权,适合需要深度定制的场景;Element Plus 适合中大型企业后台;Naive UI TypeScript 支持出色。所有现代 UI 库都依托 Tailwind CSS 实现样式系统,通过 CSS 变量实现主题切换。暗色模式通过 @nuxtjs/color-mode + Tailwind dark: 前缀轻松实现,classSuffix: '' 配置使其与 Tailwind 的 class="dark" 策略兼容。