Vue 3.2发布后,组合式API、<script setup>、Vite等新特性逐渐成熟,Vue 3的生态也越来越完善。
我用Vue 3做了几个项目,从一开始的不适应,到后来的得心应手,踩了不少坑,也积累了一些经验。本文总结Vue 3.2+生态的最佳实践,包括项目搭建、代码组织、状态管理、路由、UI组件库、性能优化、工程化等方面。
希望能帮你搭建一个现代化、高性能、易维护的Vue 3项目。
一、项目搭建
项目搭建是第一步,选对工具和配置,后面开发会顺利很多。
1. 用Vite,不要用Vue CLI
Vue 3.2+时代,首选Vite作为构建工具。
Vite的优势:
- 启动快:基于ES Module,冷启动毫秒级
- 热更新快:HMR速度极快,改代码秒级更新
- 配置简单:比webpack简单很多
- 生态好:Vue官方推荐,插件丰富
Vue CLI已经进入维护模式,新项目不要再用了。
创建项目:
npm create vite@latest my-vue-app -- --template vue或者用Vue官方的create-vue:
npm create vue@latestcreate-vue会让你选择是否需要TypeScript、Router、Pinia、Vitest等,更方便。
2. 用TypeScript
Vue 3.2+对TypeScript的支持非常好,建议新项目都用TypeScript。
好处:
- 类型安全,减少bug
- 代码提示更好,开发效率高
- 重构更安全
- 团队协作更顺畅
在<script setup>中用TypeScript非常方便:
<script setup lang="ts">
import { ref, computed } from 'vue'
interface User {
id: number
name: string
}
const user = ref<User | null>(null)
const userName = computed(() => user.value?.name ?? '未登录')
</script>3. 目录结构
推荐的目录结构:
src/
├── assets/ # 静态资源(图片、字体等)
├── components/ # 通用组件
├── composables/ # 组合式函数(hooks)
├── layouts/ # 布局组件
├── router/ # 路由配置
├── stores/ # 状态管理(Pinia)
├── styles/ # 全局样式
├── utils/ # 工具函数
├── views/ # 页面组件
├── App.vue
└── main.ts这个结构清晰,职责分明,团队协作方便。
二、组合式API和<script setup>
Vue 3.2+的核心是组合式API和<script setup>。
1. 用<script setup>,不要用普通的setup函数
<script setup>是Vue 3.2的语法糖,比普通的setup函数更简洁。
<!-- 推荐 -->
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<!-- 不推荐 -->
<script lang="ts">
import { ref, defineComponent } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
}
})
</script><script setup>的优势:
- 代码更简洁,不需要return
- 顶层的变量和函数自动暴露给模板
- 更好的TypeScript支持
- 更好的运行时性能
2. 用组合式函数(Composables)复用逻辑
组合式函数是Vue 3复用逻辑的标准方式,相当于Vue 2的mixin,但更清晰、更安全。
例子:useMouse
// composables/useMouse.ts
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(event: MouseEvent) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}使用:
<script setup>
import { useMouse } from '@/composables/useMouse'
const { x, y } = useMouse()
</script>组合式函数的命名约定:以use开头,放在composables/目录下。
3. 合理拆分组件和组合式函数
- 组件:关注UI和交互,模板和样式
- 组合式函数:关注逻辑和状态,可以在多个组件中复用
不要把所有逻辑都写在组件里,也不要把UI逻辑放到组合式函数里。合理拆分,代码更清晰。
三、状态管理:用Pinia,不要用Vuex
Vue 3.2+时代,状态管理用Pinia,不要用Vuex。
Pinia是Vue官方推荐的新状态管理库,比Vuex更简单、更好用。
1. Pinia的优势
- API更简单,没有mutations,直接修改state
- 更好的TypeScript支持
- 支持组合式API
- 更轻量,体积更小
- Vue官方推荐,Vuex 5就是Pinia
2. 定义Store
// stores/user.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserStore = defineStore('user', () => {
// state
const name = ref('')
const age = ref(0)
// getters
const isAdult = computed(() => age.value >= 18)
// actions
function setUser(newName: string, newAge: number) {
name.value = newName
age.value = newAge
}
return { name, age, isAdult, setUser }
})3. 使用Store
<script setup>
import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia'
const userStore = useUserStore()
// 用storeToRefs保持响应式
const { name, age, isAdult } = storeToRefs(userStore)
// 直接调用action
userStore.setUser('张三', 25)
</script>注意:从store中解构ref,要用storeToRefs,否则会失去响应式。
四、路由:Vue Router 4
Vue 3用Vue Router 4,和Vue 2的Vue Router 3用法差不多,但有一些变化。
1. 基本配置
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue')
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router2. 路由懒加载
用动态import实现路由懒加载,减小首屏包体积:
component: () => import('@/views/Home.vue')3. 路由守卫
router.beforeEach((to, from, next) => {
// 检查登录状态
const isLoggedIn = checkAuth()
if (to.meta.requiresAuth && !isLoggedIn) {
next('/login')
} else {
next()
}
})4. 在组合式API中使用路由
<script setup>
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
function goToAbout() {
router.push('/about')
}
</script>五、UI组件库选择
Vue 3的UI组件库已经很丰富了,根据项目需求选择。
1. Element Plus
- 最流行的Vue 3组件库,Element UI的Vue 3版本
- 组件丰富,文档完善
- 适合后台管理系统
- 支持按需引入
2. Ant Design Vue
- 蚂蚁金服的设计体系,Vue 3版本
- 设计规范,组件丰富
- 适合企业级应用
- 支持按需引入
3. Naive UI
- 比较新的Vue 3组件库,TypeScript优先
- 主题定制方便,性能好
- 组件丰富
- 适合追求现代感的项目
4. Vant
- 有赞的移动端组件库
- 适合移动端H5和小程序
- 组件丰富,文档完善
5. 选择建议
- 后台管理系统:Element Plus或Ant Design Vue
- 移动端H5:Vant
- 追求现代感和性能:Naive UI
- 特殊需求:可以自己封装组件,或用Tailwind CSS
六、样式方案
Vue 3.2+的样式方案,推荐以下几种。
1. Scoped CSS
Vue单文件组件的scoped样式,是最基本的方案:
<style scoped>
.title {
font-size: 20px;
color: #333;
}
</style>scoped样式只会作用于当前组件,不会污染全局。
2. CSS变量
用CSS变量做主题定制:
<style>
:root {
--primary-color: #409eff;
}
.button {
background-color: var(--primary-color);
}
</style>3. Tailwind CSS
如果项目需要快速开发、高度定制,可以用Tailwind CSS。
Tailwind是原子化CSS框架,用类名组合样式,不需要写CSS文件。
<template>
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
按钮
</button>
</template>Tailwind和Vue配合很好,Vite也有官方插件。
4. CSS预处理器
可以用Sass/Less/Stylus,但Vite已经内置支持,不需要额外配置太多。
建议:简单项目用scoped CSS + CSS变量,复杂项目用Tailwind CSS。
七、性能优化
Vue 3本身性能已经很好了,但还有一些优化点。
1. 合理使用v-if和v-show
- v-if:条件不满足时不渲染,适合频繁切换的场景
- v-show:始终渲染,只是切换display,适合不频繁切换的场景
不要在同一个元素上同时用v-if和v-for。
2. key的使用
v-for一定要加key,而且用稳定的key(比如id),不要用index。
<!-- 好 -->
<li v-for="item in list" :key="item.id">{{ item.name }}</li>
<!-- 不好 -->
<li v-for="(item, index) in list" :key="index">{{ item.name }}</li>3. 计算属性和侦听器
- 能用computed的,不要用watch
- computed有缓存,性能更好
- watch适合异步操作和副作用
4. 懒加载
- 路由懒加载:动态import
- 组件懒加载:defineAsyncComponent
- 图片懒加载:用v-lazy或Intersection Observer
5. 虚拟列表
长列表(几百条以上)用虚拟列表,只渲染可视区域的内容。推荐用vue-virtual-scroller。
6. 打包优化
- 用Vite的构建优化(自动代码分割、tree shaking)
- 大依赖用动态import
- 图片用WebP格式,压缩体积
- 用CDN加载第三方库
八、工程化
工程化是项目质量的保障。
1. ESLint + Prettier
- ESLint:代码规范检查
- Prettier:代码格式化
配合Vite插件,保存时自动格式化。
2. Husky + lint-staged
- Husky:Git hooks工具
- lint-staged:只检查暂存区的文件
提交代码前自动运行ESLint和Prettier,保证代码质量。
3. 单元测试
用Vitest做单元测试,Vite原生支持,速度快。
// utils/__tests__/sum.test.ts
import { describe, it, expect } from 'vitest'
import { sum } from '../sum'
describe('sum', () => {
it('adds two numbers', () => {
expect(sum(1, 2)).toBe(3)
})
})4. 组件测试
用Vue Test Utils + Vitest做组件测试。
5. CI/CD
用GitHub Actions、GitLab CI等做持续集成,自动运行测试、构建、部署。
九、常见的坑
说说Vue 3.2+开发中常见的坑。
坑一:ref和reactive的选择
- ref:适合基本类型,也可以用对象,但需要.value访问
- reactive:适合对象,不需要.value,但不能直接替换整个对象
建议:基本类型用ref,复杂对象用reactive。但团队统一用ref也可以,更一致。
坑二:解构props失去响应式
<script setup>
const props = defineProps<{ user: User }>()
// 这样会失去响应式
const { user } = props
// 要用toRefs
import { toRefs } from 'vue'
const { user } = toRefs(props)
</script>坑三:watch的 immediate 和 deep
- immediate: true:立即执行一次
- deep: true:深度监听对象内部变化
深度监听性能差,尽量避免。如果需要,考虑用computed或具体字段监听。
坑四:生命周期钩子的使用
在<script setup>中,生命周期钩子要从vue导入:
<script setup>
import { onMounted, onUnmounted } from 'vue'
onMounted(() => {
console.log('mounted')
})
</script>坑五:defineProps和defineEmits
在<script setup>中,用defineProps和defineEmits,不需要导入:
<script setup>
const props = defineProps<{ title: string }>()
const emit = defineEmits<{ (e: 'click'): void }>()
</script>十、写在最后
Vue 3.2+的生态已经非常成熟了,Vite、Pinia、Vue Router 4、TypeScript、各种UI组件库,构成了一个现代化的前端开发体系。
本文总结了我在Vue 3.2+项目中的一些最佳实践,包括项目搭建、组合式API、状态管理、路由、UI组件库、样式、性能优化、工程化等。希望能帮你少走弯路。
当然,最佳实践不是一成不变的,要根据项目的实际情况选择合适的方案。技术在发展,最佳实践也会不断更新。
2022年了,Vue 3已经成为主流。如果你还在用Vue 2,建议尽快升级到Vue 3,体验组合式API和Vite带来的开发体验提升。
最后,用一句话总结:"Vue 3.2+的最佳实践,核心是用组合式API组织逻辑,用Pinia管理状态,用Vite构建,用TypeScript保证质量。"
祝大家的Vue项目都能又快又稳。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录