02-组合式API详解

Vue 3 组合式 API 详解

1. 什么是组合式 API

组合式 API(Composition API)是 Vue 3 引入的一组新的 API,它允许开发者使用函数的方式来组织和复用组件逻辑。与 Options API 不同,组合式 API 更加灵活,便于逻辑复用和代码组织。

2. setup() 函数

基本用法

<script>
import { ref } from 'vue'

export default {
setup() {
const count = ref(0)

function increment() {
count.value++
}

return {
count,
increment
}
}
}
</script>

<script setup> 语法糖

<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
count.value++
}
</script>

<template>
<button @click="increment">{{ count }}</button>
</template>

3. 响应式 API

ref()

用于创建基本类型的响应式引用:

import { ref } from 'vue'

const count = ref(0)
const message = ref('Hello')
const isVisible = ref(true)

// 在 JS 中通过 .value 访问
console.log(count.value)

// 在模板中直接访问
// <template>{{ count }}</template>

reactive()

用于创建对象类型的响应式代理:

import { reactive } from 'vue'

const state = reactive({
count: 0,
name: 'Vue',
items: []
})

// 直接访问属性
state.count++
state.name = 'Vue 3'
state.items.push('item1')

ref vs reactive 对比

| 特性 | ref | reactive | |------|-----|----------| | 适用类型 | 任意类型 | 对象/数组 | | 访问方式 | .value | 直接访问 | | 可重新赋值 | ✅ | ❌(会失去响应性)| | 解构保持响应性 | ❌ | ❌(需用 toRefs)|

toRefs()

将响应式对象的属性转换为 ref:

import { reactive, toRefs } from 'vue'

const state = reactive({
count: 0,
name: 'Vue'
})

// 解构时保持响应性
const { count, name } = toRefs(state)

count.value++ // 会更新 state.count

4. 计算属性 computed()

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

const firstName = ref('张')
const lastName = ref('三')

// 只读计算属性
const fullName = computed(() => {
return firstName.value + ' ' + lastName.value
})

// 可写计算属性
const fullNameWritable = computed({
get() {
return firstName.value + ' ' + lastName.value
},
set(newValue) {
const [first, last] = newValue.split(' ')
firstName.value = first
lastName.value = last
}
})
</script>

5. 侦听器 watch()

侦听单个数据源

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

const keyword = ref('')

watch(keyword, (newValue, oldValue) => {
console.log('新值:', newValue)
console.log('旧值:', oldValue)
})
</script>

侦听多个数据源

import { ref, watch } from 'vue'

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

watch([x, y], ([newX, newY], [oldX, oldY]) => {
console.log(x: ${oldX} -&gt; ${newX})
console.log(y: ${oldY} -&gt; ${newY})
})

深度侦听

import { reactive, watch } from 'vue'

const state = reactive({
user: {
name: '张三',
address: {
city: '北京'
}
}
})

// reactive 对象默认深度侦听
watch(state, (newState) => {
console.log('状态变化:', newState)
})

立即执行

watch(keyword, (newValue) => {
  console.log('立即执行:', newValue)
}, { immediate: true })

6. 侦听器 watchEffect()

自动追踪依赖并执行:

import { ref, watchEffect } from 'vue'

const count = ref(0)
const name = ref('Vue')

// 自动追踪 count 和 name
watchEffect(() => {
console.log(count: ${count.value}, name: ${name.value})
})

清除副作用

watchEffect((onCleanup) => {
  const controller = new AbortController()

fetch(/api/data?q=${keyword.value}, {
signal: controller.signal
})
.then(res => res.json())
.then(data => {
results.value = data
})

// 下次副作用运行时或侦听器停止时调用
onCleanup(() => controller.abort())
})

7. 生命周期钩子

<script setup>
import {
  onMounted,
  onUpdated,
  onUnmounted,
  onBeforeMount,
  onBeforeUpdate,
  onBeforeUnmount
} from 'vue'

onBeforeMount(() => {
console.log('挂载前')
})

onMounted(() => {
console.log('挂载完成')
// 适合:DOM 操作、发起网络请求、添加事件监听
})

onBeforeUpdate(() => {
console.log('更新前')
})

onUpdated(() => {
console.log('更新完成')
})

onBeforeUnmount(() => {
console.log('卸载前')
// 适合:清理定时器、移除事件监听
})

onUnmounted(() => {
console.log('卸载完成')
})
</script>

8. 模板引用 ref

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

const inputRef = ref(null)
const childRef = ref(null)

onMounted(() => {
// 访问 DOM 元素
inputRef.value.focus()

// 访问子组件实例
childRef.value.childMethod()
})
</script>

<template>
<input ref="inputRef" type="text" />
<ChildComponent ref="childRef" />
</template>

9. 自定义 Hook(组合函数)

鼠标位置追踪

// 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 './useMouse'

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

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

异步请求

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

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

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

try {
const response = await fetch(url.value)
if (!response.ok) throw new Error('请求失败')
data.value = await response.json()
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
}

watchEffect(() => {
fetchData()
})

return { data, error, loading }
}

<script setup>
import { useFetch } from './useFetch'
import { computed } from 'vue'

const userId = ref(1)
const url = computed(() => `https://api.example.com/users/${userId.value}`)

const { data, error, loading } = useFetch(url)
</script>

<template>
  <div v-if="loading">加载中...</div>
  <div v-else-if="error">错误: {{ error }}</div>
  <div v-else>
    <p>姓名: {{ data.name }}</p>
    <p>邮箱: {{ data.email }}</p>
  </div>
</template>

10. provide / inject

基础用法

<!-- 父组件 -->
<script setup>
import { provide, ref } from 'vue'

const theme = ref('light')
const user = ref({ name: '张三' })

provide('theme', theme)
provide('user', user)

function toggleTheme() {
theme.value = theme.value === 'light' ? 'dark' : 'light'
}
</script>

<!-- 子孙组件(任意层级) -->
<script setup>
import { inject } from 'vue'

const theme = inject('theme')
const user = inject('user')

// 提供默认值
const config = inject('config', { language: 'zh-CN' })
</script>

<template>
  <p>当前主题: {{ theme }}</p>
  <p>用户: {{ user.name }}</p>
</template>

小结

组合式 API 是 Vue 3 的核心特性,它提供了更灵活的代码组织方式:

  • setup()<script setup> 是组合式 API 的入口
  • 响应式 API(ref、reactive)管理状态
  • computedwatch 处理派生状态和副作用
  • 生命周期钩子 处理组件生命周期事件
  • 自定义 Hook 实现逻辑复用
  • provide/inject 实现跨层级通信
posted @ 2026-06-16 13:06  心梦EGO  阅读(6)  评论(0)    收藏  举报