Vue3 Composition API 实战指南
文章目录
- Vue3 Composition API 实战指南
- 前言
- 为什么选择 Composition API?
- 核心优势
- 基础语法对比
- 实战场景一:用户认证管理
- 实战场景二:数据获取与缓存
- 实战场景三:表单验证
- 实战场景四:主题切换
- 与 Options API 的选择
- 何时使用 Composition API?
- 何时使用 Options API?
- 最佳实践
- 1. 组合式函数命名
- 2. 返回值使用 readonly
- 3. 合理使用 ref 和 reactive
- 总结
Vue3 Composition API 实战指南
通过实际场景掌握 Vue3 Composition API 的核心用法
前言
Vue3 的 Composition API 改变了我们编写 Vue 组件的方式。相比 Options API,它提供了更好的逻辑复用、类型推导和代码组织能力。本文将通过几个实战场景,帮你快速掌握 Composition API 的精髓。
为什么选择 Composition API?
核心优势
- 逻辑复用更简单:通过组合式函数轻松复用逻辑
- 更好的 TypeScript 支持:完整的类型推导
- 代码组织更灵活:相关逻辑可以组织在一起
- 性能更优:支持 tree-shaking,按需引入
基础语法对比
<!-- Options API -->
<script>
export default {data() {return { count: 0 }},methods: {increment() { this.count++ }}
}
</script><!-- Composition API -->
<script setup>
import { ref } from 'vue'const count = ref(0)
const increment = () => count.value++
</script>
实战场景一:用户认证管理
让我们从一个常见的用户认证场景开始:
// composables/useAuth.ts
import { ref, computed } from 'vue'const currentUser = ref(null)
const loading = ref(false)export function useAuth() {const isAuthenticated = computed(() => !!currentUser.value)const login = async (credentials) => {loading.value = truetry {const response = await fetch('/api/auth/login', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify(credentials)})if (response.ok) {currentUser.value = await response.json()return { success: true }}} catch (error) {return { success: false, error: error.message }} finally {loading.value = false}}const logout = () => {currentUser.value = nulllocalStorage.removeItem('auth_token')}return {currentUser: readonly(currentUser),loading: readonly(loading),isAuthenticated,login,logout}
}
在组件中使用:
<template><div><div v-if="isAuthenticated"><p>欢迎,{{ currentUser.name }}!</p><button @click="logout">退出登录</button></div><div v-else><button @click="handleLogin" :disabled="loading">{{ loading ? '登录中...' : '登录' }}</button></div></div>
</template><script setup>
import { useAuth } from '@/composables/useAuth'const { currentUser, loading, isAuthenticated, login, logout } = useAuth()const handleLogin = async () => {const result = await login({email: 'user@example.com',password: 'password'})if (!result.success) {alert('登录失败:' + result.error)}
}
</script>
实战场景二:数据获取与缓存
创建一个通用的数据获取 Hook:
// composables/useFetch.ts
import { ref, watchEffect } from 'vue'export function useFetch(url) {const data = ref(null)const loading = ref(false)const error = ref(null)const fetchData = async () => {loading.value = trueerror.value = nulltry {const response = await fetch(url.value || url)if (!response.ok) throw new Error('请求失败')data.value = await response.json()} catch (err) {error.value = err.message} finally {loading.value = false}}// 自动监听 URL 变化watchEffect(() => {if (url.value || url) {fetchData()}})return { data, loading, error, refresh: fetchData }
}
使用示例:
<template><div><div v-if="loading">加载中...</div><div v-else-if="error">错误:{{ error }}</div><div v-else><h2>用户列表</h2><ul><li v-for="user in data" :key="user.id">{{ user.name }} - {{ user.email }}</li></ul><button @click="refresh">刷新</button></div></div>
</template><script setup>
import { useFetch } from '@/composables/useFetch'const { data, loading, error, refresh } = useFetch('/api/users')
</script>
实战场景三:表单验证
创建一个简单而强大的表单验证 Hook:
// composables/useForm.ts
import { reactive, computed } from 'vue'export function useForm(initialData, rules = {}) {const formData = reactive({ ...initialData })const errors = reactive({})const validateField = (field) => {const value = formData[field]const fieldRules = rules[field] || []for (const rule of fieldRules) {if (rule.required && !value) {errors[field] = '此字段为必填项'return false}if (rule.minLength && value.length < rule.minLength) {errors[field] = `最少需要 ${rule.minLength} 个字符`return false}if (rule.pattern && !rule.pattern.test(value)) {errors[field] = '格式不正确'return false}}delete errors[field]return true}const validateForm = () => {let isValid = trueObject.keys(rules).forEach(field => {if (!validateField(field)) {isValid = false}})return isValid}const isValid = computed(() => Object.keys(errors).length === 0)return {formData,errors,isValid,validateField,validateForm}
}
在登录表单中使用:
<template><form @submit.prevent="handleSubmit"><div><input v-model="formData.email" @blur="validateField('email')"placeholder="邮箱":class="{ error: errors.email }"/><span v-if="errors.email" class="error-text">{{ errors.email }}</span></div><div><input v-model="formData.password" @blur="validateField('password')"type="password" placeholder="密码":class="{ error: errors.password }"/><span v-if="errors.password" class="error-text">{{ errors.password }}</span></div><button type="submit" :disabled="!isValid">登录</button></form>
</template><script setup>
import { useForm } from '@/composables/useForm'
import { useAuth } from '@/composables/useAuth'const { login } = useAuth()const { formData, errors, isValid, validateField, validateForm } = useForm({ email: '', password: '' },{email: [{ required: true },{ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ }],password: [{ required: true },{ minLength: 6 }]}
)const handleSubmit = async () => {if (!validateForm()) returnconst result = await login(formData)if (!result.success) {alert('登录失败')}
}
</script>
实战场景四:主题切换
实现一个完整的主题切换功能:
// composables/useTheme.ts
import { ref, watch, onMounted } from 'vue'const currentTheme = ref('light')export function useTheme() {const isDark = computed(() => currentTheme.value === 'dark')const setTheme = (theme) => {currentTheme.value = themedocument.documentElement.classList.toggle('dark', theme === 'dark')localStorage.setItem('theme', theme)}const toggleTheme = () => {setTheme(currentTheme.value === 'light' ? 'dark' : 'light')}onMounted(() => {const savedTheme = localStorage.getItem('theme') || 'light'setTheme(savedTheme)})return {currentTheme: readonly(currentTheme),isDark,setTheme,toggleTheme}
}
使用主题切换:
<template><button @click="toggleTheme" class="theme-toggle">{{ isDark ? '🌙' : '☀️' }}{{ isDark ? '深色模式' : '浅色模式' }}</button>
</template><script setup>
import { useTheme } from '@/composables/useTheme'const { isDark, toggleTheme } = useTheme()
</script><style>
.theme-toggle {padding: 8px 16px;border: none;border-radius: 4px;background: var(--bg-color);color: var(--text-color);cursor: pointer;
}:root {--bg-color: #ffffff;--text-color: #333333;
}:root.dark {--bg-color: #1a1a1a;--text-color: #ffffff;
}
</style>
与 Options API 的选择
何时使用 Composition API?
- ✅ 复杂的组件逻辑
- ✅ 需要逻辑复用
- ✅ TypeScript 项目
- ✅ 大型项目
何时使用 Options API?
- ✅ 简单的组件
- ✅ 团队更熟悉 Options API
- ✅ 快速原型开发
最佳实践
1. 组合式函数命名
// ✅ 使用 use 前缀
export function useAuth() {}
export function useTheme() {}// ❌ 避免
export function auth() {}
export function theme() {}
2. 返回值使用 readonly
export function useCounter() {const count = ref(0)return {count: readonly(count), // 防止外部直接修改increment: () => count.value++}
}
3. 合理使用 ref 和 reactive
// ✅ 基本类型用 ref
const count = ref(0)
const message = ref('')// ✅ 对象用 reactive
const user = reactive({name: '',email: ''
})
总结
Composition API 为 Vue3 带来了更强大的逻辑组织和复用能力。通过本文的实战场景,你应该能够:
- 理解核心概念:ref、reactive、computed、watch 的使用
- 掌握实战技巧:如何创建可复用的组合式函数
- 应用最佳实践:代码组织和性能优化
记住,选择合适的 API 比使用最新的 API 更重要。根据项目需求和团队情况,做出明智的技术选择。
开始你的 Vue3 Composition API 之旅吧!如果你有任何问题,欢迎在评论区讨论。
