Vue 3 Composition API 实战指南

Composition API 简介

Vue 3 引入的 Composition API 是 Vue 生态系统中最重要的变革之一。它提供了一种更灵活、更强大的方式来组织和复用组件逻辑,特别适合处理复杂组件和大型应用。

Options API vs Composition API

Options API(传统方式)

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <button @click="decrement">Decrement</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    },
    decrement() {
      this.count--
    }
  },
  watch: {
    count(newVal, oldVal) {
      console.log(`Count changed from ${oldVal} to ${newVal}`)
    }
  },
  mounted() {
    console.log("Component mounted")
  }
}
</script>

Composition API(现代方式)

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <button @click="decrement">Decrement</button>
  </div>
</template>

<script setup>
import { ref, watch, onMounted } from 'vue'

// 响应式数据
const count = ref(0)

// 方法
const increment = () => {
  count.value++
}

const decrement = () => {
  count.value--
}

// 监听器
watch(count, (newVal, oldVal) => {
  console.log(`Count changed from ${oldVal} to ${newVal}`)
})

// 生命周期钩子
onMounted(() => {
  console.log("Component mounted")
})
</script>

核心响应式 API

1. ref – 创建响应式引用

import { ref } from 'vue'

// 基本类型
const count = ref(0)
console.log(count.value) // 0
count.value = 1

// 对象类型
const user = ref({
  name: '张三',
  age: 25
})
user.value.name = '李四'

2. reactive – 创建响应式对象

import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: {
    name: '王五',
    age: 30
  },
  items: ['item1', 'item2']
})

// 直接访问属性,不需要 .value
console.log(state.count) // 0
state.count = 1
state.items.push('item3')

3. computed – 计算属性

import { ref, computed } from 'vue'

const price = ref(100)
const quantity = ref(2)

// 计算总价
const total = computed(() => {
  return price.value * quantity.value
})

console.log(total.value) // 200

// 可写的计算属性
const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  set(newValue) {
    const [first, last] = newValue.split(' ')
    firstName.value = first
    lastName.value = last
  }
})

4. watch 和 watchEffect – 监听器

import { ref, watch, watchEffect } from 'vue'

const count = ref(0)
const double = ref(0)

// watch - 精确监听
watch(count, (newVal, oldVal) => {
  console.log(`Count changed: ${oldVal} → ${newVal}`)
  double.value = newVal * 2
}, {
  immediate: true, // 立即执行
  deep: true      // 深度监听
})

// watchEffect - 自动追踪依赖
watchEffect(() => {
  console.log(`Count is: ${count.value}`)
  // 自动追踪 count.value 的依赖
})

自定义组合函数

示例1:鼠标位置追踪

// useMouse.js
export function useMouse() {
  import { ref, onMounted, onUnmounted } from 'vue'

  const x = ref(0)
  const y = ref(0)

  const update = (event) => {
    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 './useMouse'

const { x, y } = useMouse()
</script>

<template>
  <div>Mouse position: {{ x }}, {{ y }}</div>
</template>

示例2:数据获取 Hook

// useFetch.js
export function useFetch(url) {
  import { ref, onMounted } from 'vue'

  const data = ref(null)
  const loading = ref(true)
  const error = ref(null)

  const fetchData = async () => {
    try {
      loading.value = true
      const response = await fetch(url)
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`)
      }
      data.value = await response.json()
    } catch (e) {
      error.value = e
    } finally {
      loading.value = false
    }
  }

  onMounted(fetchData)

  return {
    data,
    loading,
    error,
    refetch: fetchData
  }
}

// 在组件中使用
<script setup>
import { useFetch } from './useFetch'

const { data, loading, error } = useFetch('https://api.example.com/users')
</script>

实际应用场景

场景1:表单处理

<script setup>
import { reactive, computed } from 'vue'

const form = reactive({
  username: '',
  email: '',
  password: '',
  confirmPassword: ''
})

const errors = reactive({})

// 表单验证
const isValid = computed(() => {
  errors.username = form.username ? '' : '用户名不能为空'
  errors.email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email) ? '' : '邮箱格式不正确'
  errors.password = form.password.length >= 6 ? '' : '密码至少6位'
  errors.confirmPassword = form.password === form.confirmPassword ? '' : '两次密码不一致'
  
  return !Object.values(errors).some(error => error)
})

const submit = () => {
  if (isValid.value) {
    console.log('表单提交:', form)
    // 发送到API
  }
}
</script>

场景2:状态管理

// store.js - 简单的状态管理
import { reactive } from 'vue'

export const store = reactive({
  user: null,
  token: null,
  cart: [],
  
  login(userData) {
    this.user = userData.user
    this.token = userData.token
    localStorage.setItem('token', userData.token)
  },
  
  logout() {
    this.user = null
    this.token = null
    localStorage.removeItem('token')
  },
  
  addToCart(item) {
    this.cart.push(item)
  },
  
  removeFromCart(itemId) {
    this.cart = this.cart.filter(item => item.id !== itemId)
  }
})

// 在组件中使用
<script setup>
import { store } from './store'

const cartCount = computed(() => store.cart.length)
</script>

最佳实践

  1. 逻辑复用:将相关逻辑提取到自定义组合函数中
  2. 命名规范:组合函数以”use”开头,如 useUser、useFetch
  3. 单一职责:每个组合函数只关注一个特定的功能
  4. 类型安全:使用 TypeScript 获得更好的类型支持
  5. 性能优化:合理使用 computed 和 watch,避免不必要的重新计算

总结

Composition API 为 Vue 开发带来了革命性的变化。它提供了更灵活、更强大的代码组织方式,特别适合处理复杂组件和大型应用。通过自定义组合函数,我们可以实现逻辑的高度复用,提高代码的可维护性和可测试性。

虽然学习曲线比 Options API 稍陡,但一旦掌握,你会发现它能让你的 Vue 代码更加优雅和强大。建议在实际项目中逐步尝试 Composition API,从简单的组件开始,逐步应用到更复杂的场景中。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容