首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Vue3 Composition API 实战指南

Vue3 Composition API 实战指南

作者头像
fruge365
发布2025-12-15 13:13:17
发布2025-12-15 13:13:17
290
举报

Vue3 Composition API 实战指南

通过实际场景掌握 Vue3 Composition API 的核心用法

前言

Vue3 的 Composition API 改变了我们编写 Vue 组件的方式。相比 Options API,它提供了更好的逻辑复用、类型推导和代码组织能力。本文将通过几个实战场景,帮你快速掌握 Composition API 的精髓。

为什么选择 Composition API?

核心优势
  • 逻辑复用更简单:通过组合式函数轻松复用逻辑
  • 更好的 TypeScript 支持:完整的类型推导
  • 代码组织更灵活:相关逻辑可以组织在一起
  • 性能更优:支持 tree-shaking,按需引入
基础语法对比
代码语言:javascript
复制
<!-- 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>

实战场景一:用户认证管理

让我们从一个常见的用户认证场景开始:

代码语言:javascript
复制
// 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 = true
    try {
      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 = null
    localStorage.removeItem('auth_token')
  }
  
  return {
    currentUser: readonly(currentUser),
    loading: readonly(loading),
    isAuthenticated,
    login,
    logout
  }
}

在组件中使用:

代码语言:javascript
复制
<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:

代码语言:javascript
复制
// 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 = true
    error.value = null
    
    try {
      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 }
}

使用示例:

代码语言:javascript
复制
<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:

代码语言:javascript
复制
// 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 = true
    Object.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
  }
}

在登录表单中使用:

代码语言:javascript
复制
<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()) return
  
  const result = await login(formData)
  if (!result.success) {
    alert('登录失败')
  }
}
</script>

实战场景四:主题切换

实现一个完整的主题切换功能:

代码语言:javascript
复制
// 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 = theme
    document.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
  }
}

使用主题切换:

代码语言:javascript
复制
<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. 组合式函数命名
代码语言:javascript
复制
// ✅ 使用 use 前缀
export function useAuth() {}
export function useTheme() {}

// ❌ 避免
export function auth() {}
export function theme() {}
2. 返回值使用 readonly
代码语言:javascript
复制
export function useCounter() {
  const count = ref(0)
  
  return {
    count: readonly(count), // 防止外部直接修改
    increment: () => count.value++
  }
}
3. 合理使用 ref 和 reactive
代码语言:javascript
复制
// ✅ 基本类型用 ref
const count = ref(0)
const message = ref('')

// ✅ 对象用 reactive
const user = reactive({
  name: '',
  email: ''
})

总结

Composition API 为 Vue3 带来了更强大的逻辑组织和复用能力。通过本文的实战场景,你应该能够:

  1. 理解核心概念:ref、reactive、computed、watch 的使用
  2. 掌握实战技巧:如何创建可复用的组合式函数
  3. 应用最佳实践:代码组织和性能优化

记住,选择合适的 API 比使用最新的 API 更重要。根据项目需求和团队情况,做出明智的技术选择。


开始你的 Vue3 Composition API 之旅吧!如果你有任何问题,欢迎在评论区讨论。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Vue3 Composition API 实战指南
    • 前言
    • 为什么选择 Composition API?
      • 核心优势
      • 基础语法对比
    • 实战场景一:用户认证管理
    • 实战场景二:数据获取与缓存
    • 实战场景三:表单验证
    • 实战场景四:主题切换
    • 与 Options API 的选择
      • 何时使用 Composition API?
      • 何时使用 Options API?
    • 最佳实践
      • 1. 组合式函数命名
      • 2. 返回值使用 readonly
      • 3. 合理使用 ref 和 reactive
    • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档