Files
home/docs/vue/composition.md
2026-05-13 16:24:00 +08:00

243 lines
3.8 KiB
Markdown

# 组合式API
## setup函数
### 基本用法
```vue
<script setup>
import { ref, reactive, computed, watch, onMounted } from 'vue'
// 响应式数据
const count = ref(0)
const state = reactive({
name: 'Vue',
version: 3
})
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 方法
function increment() {
count.value++
}
// 生命周期
onMounted(() => {
console.log('组件已挂载')
})
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ doubleCount }}</p>
<button @click="increment">+1</button>
</div>
</template>
```
## ref与reactive
### ref
用于基本类型和需要替换整个对象的场景。
```vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
const user = ref({ name: '张三' })
// 访问需要 .value
console.log(count.value)
console.log(user.value.name)
// 重新赋值
user.value = { name: '李四' }
</script>
```
### reactive
用于对象类型,返回原始对象的代理。
```vue
<script setup>
import { reactive } from 'vue'
const state = reactive({
count: 0,
user: {
name: '张三',
age: 25
}
})
// 直接访问,不需要 .value
console.log(state.count)
console.log(state.user.name)
// 修改属性
state.count++
state.user.age = 26
</script>
```
## 组合式函数
### 创建组合式函数
```javascript
// useCounter.js
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
function decrement() {
count.value--
}
function reset() {
count.value = initialValue
}
return {
count,
doubleCount,
increment,
decrement,
reset
}
}
```
### 使用组合式函数
```vue
<script setup>
import { useCounter } from './useCounter'
const { count, doubleCount, increment, decrement, reset } = useCounter(10)
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ doubleCount }}</p>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
<button @click="reset">Reset</button>
</div>
</template>
```
### 鼠标位置追踪
```javascript
// 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 }
}
```
```vue
<script setup>
import { useMouse } from './useMouse'
const { x, y } = useMouse()
</script>
<template>
<p>鼠标位置: {{ x }}, {{ y }}</p>
</template>
```
## provide/inject
### 提供数据
```vue
<!-- 祖先组件 -->
<script setup>
import { provide, ref } from 'vue'
const theme = ref('dark')
const user = ref({ name: '张三' })
provide('theme', theme)
provide('user', user)
provide('updateTheme', (newTheme) => {
theme.value = newTheme
})
</script>
```
### 注入数据
```vue
<!-- 后代组件 -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme', 'light') // 默认值
const user = inject('user')
const updateTheme = inject('updateTheme')
function toggleTheme() {
updateTheme(theme.value === 'dark' ? 'light' : 'dark')
}
</script>
```
## toRef与toRefs
```vue
<script setup>
import { reactive, toRef, toRefs } from 'vue'
const state = reactive({
name: '张三',
age: 25,
city: '北京'
})
// toRef - 单个属性
const nameRef = toRef(state, 'name')
// toRefs - 所有属性
const { name, age, city } = toRefs(state)
// 解构后的ref保持响应性
name.value = '李四'
console.log(state.name) // 李四
</script>
```