主题
概述
Vue 3 是一个渐进式 JavaScript 框架,专注于构建用户界面。它以易学易用著称,同时通过 Composition API 和 TypeScript 支持,也能满足大型应用的需求。
Vue 3 核心优势
- 易学易用:渐进式架构,按需学习,上手门槛低
- Composition API:逻辑复用更优雅,TypeScript 支持更好
- 响应式系统:基于 Proxy 的响应式,性能更优
- 生态完善:Pinia、Vue Router、VueUse 等配套成熟
推荐技术栈
以下是我们为 Vue 3 项目精选的技术组合,适合中小型项目,开发体验好且维护成本低:
🎯 推荐技术选型
| 类别 | 推荐方案 | 说明 |
|---|---|---|
| 样式方案 | UnoCSS | 原子化 CSS,属性模式可读性极佳 |
| 状态管理 | Pinia | Vue 官方推荐,简单直观 |
| 数据请求 | TanStack Query | 自动缓存、后台更新、请求去重 |
| 表单校验 | TanStack Form + Zod | 类型安全的表单方案 |
| 工具函数 | VueUse | 最全面的 Vue 组合式工具库 |
⚠️ 关于代码规范工具链
生成的项目只配置了基础的 ESLint。由于 Biome、oxlint、oxfmt 等代码规范工具选项较多,且不同团队偏好不同,我们不做统一适配。
如需更完善的代码规范,请根据团队需求自行配置 ESLint、Prettier 或 Biome。
技术特性
| 特性 | 说明 |
|---|---|
| 编程语言 | TypeScript (推荐) / JavaScript |
| 组件规范 | Composition API + <script setup> |
| 构建工具 | Vite |
| 状态管理 | Pinia (全局) / Composables (局部) |
| 数据请求 | TanStack Query (Vue Query) |
| 路由方案 | Vue Router v4 |
| 样式方案 | UnoCSS (推荐) / TailwindCSS / Scoped CSS |
| 工具库 | VueUse |
Vue 3 子文档导航
| 文档 | 说明 |
|---|---|
| 项目结构 | 生成项目的目录结构说明 |
| Composition API | 组件设计与组合式 API 最佳实践 |
| TanStack Query | 数据请求与缓存管理 |
| Pinia 状态管理 | 全局状态管理方案 |
| VueUse 工具库 | 常用组合式工具函数 |
| 表单校验 | TanStack Form + Zod 表单方案 |
| 图表集成 | vue-echarts 图表最佳实践 |
| Excel 导入导出 | ExcelJS 数据处理 |
| UnoCSS 样式方案 | 原子化 CSS 使用指南 |
生成的项目结构
ThesisAI 生成的 Vue 3 项目遵循以下结构:
frontend
src
api // API 客户端
client.ts // HTTP 客户端封装
[module].ts // 各模块 API
assets // 静态资源
components // 通用组件
ui // UI 组件(shadcn-vue 等)
FileUpload.vue // 文件上传组件
composables // 组合式函数
use[Feature].ts // 业务 composables
config // 配置文件
nav.ts // 导航配置
layouts // 布局组件
DefaultLayout.vue // 默认布局
AdminLayout.vue // 管理后台布局
SidebarLayout.vue // 侧边栏布局
AuthLayout.vue // 认证页面布局
router // 路由配置
index.ts
stores // Pinia 状态管理
auth.ts // 认证状态
types // TypeScript 类型
utils // 工具函数
format.ts // 格式化工具
validators.ts // 校验工具
excel.ts // Excel 工具
views // 页面组件
admin // 管理后台页面
[page].vue // 其他页面
App.vue // 根组件
main.ts // 入口文件
public // 公共资源
index.html
vite.config.ts
tailwind.config.js
tsconfig.json
package.json
内置布局组件
生成的项目已内置多种布局组件,无需重复创建:
| 布局组件 | 说明 | 适用场景 |
|---|---|---|
DefaultLayout | 顶部导航布局 | 普通用户端、公开页面 |
SidebarLayout | 顶部导航 + 左侧边栏 | 需要侧边菜单的场景 |
AdminLayout | 管理后台侧边栏布局 | 管理员后台页面 |
AuthLayout | 认证页面布局 | 登录/注册页面 |
所有布局都已支持响应式(移动端自动变为抽屉菜单)。
开发环境
环境要求
| 依赖 | 版本要求 | 说明 |
|---|---|---|
| Node.js | >= 18.0 | 推荐 LTS 版本 |
| pnpm | >= 8.0 | 包管理器 |
安装依赖
bash
$
cd frontend && pnpm install
启动开发服务器
bash
$
pnpm dev
服务启动成功
- 开发地址:
http://localhost:5173 - 热更新: 已启用,修改代码自动刷新
核心开发模式
1. 使用 <script setup> 语法
Vue 3 推荐使用 <script setup> 语法糖,更简洁高效:
UserCard.vue
vue
<script setup lang="ts">
import { computed } from 'vue'
// Props 定义
interface Props {
name: string
email: string
age?: number
}
const props = defineProps<Props>()
// Emits 定义
interface Emits {
(e: 'select', id: string): void
(e: 'delete'): void
}
const emit = defineEmits<Emits>()
// 计算属性
const displayName = computed(() => props.name.toUpperCase())
// 方法
const handleSelect = () => {
emit('select', 'user-id')
}
</script>
<template>
<div class="user-card" @click="handleSelect">
<h3>{{ displayName }}</h3>
<p>{{ props.email }}</p>
</div>
</template>2. 使用 defineModel 实现双向绑定
Vue 3.4+ 的新特性,简化 v-model 实现:
SearchInput.vue
vue
<script setup lang="ts">
// defineModel 自动创建 props 和 emit
const keyword = defineModel<string>('keyword', { default: '' })
const category = defineModel<string>('category', { default: 'all' })
</script>
<template>
<div class="flex gap-2">
<Input v-model="keyword" placeholder="搜索关键词" />
<Select v-model="category">
<SelectItem value="all">全部</SelectItem>
<SelectItem value="article">文章</SelectItem>
</Select>
</div>
</template>父组件使用:
父组件使用
vue
<template>
<SearchInput v-model:keyword="searchKeyword" v-model:category="searchCategory" />
</template>3. 可选链操作符
在模板中使用可选链,避免 undefined 错误:
安全访问
vue
<template>
<div>
<!-- ✅ 正确:使用可选链 -->
<p>{{ user?.name }}</p>
<p>{{ user?.profile?.avatar }}</p>
<!-- ❌ 错误:可能报错 -->
<p>{{ user.name }}</p>
</div>
</template>HTTP 客户端
项目已封装好 HTTP 客户端,位于 @/api/client.ts,统一处理:
- 请求/响应拦截
- 错误处理与 Toast 提示
- Token 自动注入
- 响应数据解构
api/user.ts
typescript
import { httpClient } from './client'
interface User {
id: number
name: string
email: string
}
export const userApi = {
getAll: () => httpClient.get<User[]>('/users'),
getById: (id: number) => httpClient.get<User>(`/users/${id}`),
create: (data: Omit<User, 'id'>) => httpClient.post<User>('/users', data),
update: (id: number, data: Partial<User>) => httpClient.patch<User>(`/users/${id}`, data),
delete: (id: number) => httpClient.delete(`/users/${id}`),
}无需手动处理错误
HTTP 客户端已统一处理错误并显示 Toast,业务代码无需 try-catch。
typescript
// 直接获取数据,类型安全
const user = await userApi.getById(1) // user 类型是 User工具函数
项目内置常用工具函数,位于 @/utils/:
格式化工具 @/utils/format.ts
typescript
import { formatDate, formatCurrency, formatRelativeTime } from '@/utils/format'
formatDate(new Date()) // '2024-01-15'
formatDate(date, 'YYYY-MM-DD HH:mm') // '2024-01-15 14:30'
formatCurrency(1234.56) // '¥1,234.56'
formatRelativeTime(date) // '3 天前'校验工具 @/utils/validators.ts
typescript
import { isEmail, isPhone, isUrl } from '@/utils/validators'
isEmail('test@example.com') // true
isPhone('13800138000') // true
isUrl('https://example.com') // true生产构建
bash
$
pnpm build
构建产物位于 dist/ 目录,可直接部署到 Nginx 或 CDN。