Composition API 逻辑复用

使用组合式函数实现 Vue 3 逻辑复用

问题

Vue 3 Composition API 如何实现逻辑复用?与 Vue 2 的 mixins 有什么区别?

解答

Composition API 通过**组合式函数(Composables)**实现逻辑复用。组合式函数是以 use 开头的函数,封装并返回响应式状态和方法。

基础示例:useMouse

// composables/useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useMouse() {
  // 响应式状态
  const x = ref(0)
  const y = ref(0)

  // 更新状态的方法
  function 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 './composables/useMouse'

// 直接解构使用
const { x, y } = useMouse()
</script>

<template>
  <p>鼠标位置: {{ x }}, {{ y }}</p>
</template>

实用示例:useFetch

// composables/useFetch.js
import { ref, watchEffect, toValue } from 'vue'

export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)
  const loading = ref(false)

  async function fetchData() {
    loading.value = true
    data.value = null
    error.value = null

    try {
      // toValue() 处理 ref 或 getter
      const res = await fetch(toValue(url))
      data.value = await res.json()
    } catch (e) {
      error.value = e
    } finally {
      loading.value = false
    }
  }

  // 响应式地追踪 url 变化
  watchEffect(() => {
    fetchData()
  })

  return { data, error, loading, refetch: fetchData }
}
<script setup>
import { ref } from 'vue'
import { useFetch } from './composables/useFetch'

const userId = ref(1)
// url 变化时自动重新请求
const { data, loading, error } = useFetch(
  () => `https://api.example.com/users/${userId.value}`
)
</script>

组合多个 Composables

// composables/useUserStatus.js
import { computed } from 'vue'
import { useFetch } from './useFetch'
import { useLocalStorage } from './useLocalStorage'

export function useUserStatus(userId) {
  // 组合其他 composables
  const { data: user, loading } = useFetch(`/api/users/${userId}`)
  const { value: lastVisit, setValue } = useLocalStorage('lastVisit')

  // 基于组合数据计算
  const isOnline = computed(() => user.value?.status === 'online')

  function recordVisit() {
    setValue(new Date().toISOString())
  }

  return { user, loading, isOnline, lastVisit, recordVisit }
}

与 Mixins 对比

// Vue 2 Mixins - 存在问题
const mousePositionMixin = {
  data() {
    return { x: 0, y: 0 } // 来源不清晰,可能命名冲突
  },
  mounted() { /* ... */ }
}

// Vue 3 Composables - 解决问题
const { x, y } = useMouse()           // 来源清晰
const { x: mouseX } = useMouse()      // 可重命名避免冲突

关键点

  • 组合式函数以 use 开头,返回响应式状态和方法
  • 来源清晰,可通过解构重命名避免冲突
  • 支持接收 ref 或 getter 作为参数,实现响应式输入
  • 可以自由组合多个 composables,灵活度高
  • 相比 mixins:无命名冲突、类型推导友好、逻辑来源明确