组合式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>