深入探索Vue 3组合式API
- [深入探索Vue 3组合式API](#深入探索Vue 3组合式API)
 - 
- 一、组合式API诞生背景
 - 
- [1.1 Options API的局限性](#1.1 Options API的局限性)
 - [1.2 设计目标](#1.2 设计目标)
 - 二、核心概念解析
 - 
- [2.1 setup() 函数:组合式API的基石](#2.1 setup() 函数:组合式API的基石)
 - [2.2 响应式系统:重新定义数据驱动](#2.2 响应式系统:重新定义数据驱动)
 - [2.3 生命周期:全新的接入方式](#2.3 生命周期:全新的接入方式)
 - [2.4 响应式原理探秘](#2.4 响应式原理探秘)
 - [2.5 组合式API中的上下文处理](#2.5 组合式API中的上下文处理)
 
 
 - 三、核心API深度解析
 - 
- [3.1 响应式工具](#3.1 响应式工具)
 - [3.2 计算属性](#3.2 计算属性)
 - [3.3 副作用管理](#3.3 副作用管理)
 
 - 四、逻辑复用模式
 - 
- [4.1 自定义组合函数](#4.1 自定义组合函数)
 - [4.2 异步状态管理](#4.2 异步状态管理)
 
 - 五、最佳实践
 - 
- [5.1 代码组织模式](#5.1 代码组织模式)
 - [5.2 TypeScript集成](#5.2 TypeScript集成)
 
 - [六、与Options API对比](#六、与Options API对比)
 - 
- [6.1 逻辑组织对比](#6.1 逻辑组织对比)
 
 
 
深入探索Vue 3组合式API
一、组合式API诞生背景
1.1 Options API的局限性
- 代码组织碎片化
 - 逻辑复用困难(mixins缺陷)
 - 类型支持不足
 
1.2 设计目标
- 更好的逻辑复用
 - 更灵活的组织方式
 - 更好的类型推导
 - 渐进式采用策略
 
二、核心概念解析
2.1 setup() 函数:组合式API的基石
(1)函数特性与执行时机
            
            
              javascript
              
              
            
          
          export default {
  setup(props, context) {
    // 在beforeCreate之前执行
    // 无法访问this
    // 返回对象将暴露给模板和其他选项
  }
}
        - 执行顺序 :在组件实例创建之前同步执行,位于
beforeCreate和created生命周期之间 - 参数解析 :
props:响应式的props对象,结构会失去响应性context:包含attrs、slots、emit的非响应式对象
 - 返回值 :
- 返回对象属性将合并到模板渲染上下文
 - 可返回渲染函数直接控制视图输出
 
 
(2)props处理规范
            
            
              typescript
              
              
            
          
          import { defineComponent } from 'vue'
interface Props {
  title: string
  count?: number
}
export default defineComponent({
  props: {
    title: String,
    count: {
      type: Number,
      default: 0
    }
  },
  setup(props: Props) {
    // 使用watch监听props变化
    watch(() => props.count, (newVal) => {
      console.log('count changed:', newVal)
    })
  }
})
        - 类型安全:配合TypeScript实现严格类型校验
 - 不可解构 :直接解构props会导致响应性丢失,需使用
toRefs - 默认值处理:当父组件未传值时自动应用默认值
 
(3)上下文对象解析
            
            
              javascript
              
              
            
          
          setup(props, { attrs, slots, emit, expose }) {
  // 访问非响应式属性:
  console.log(attrs.class)
  
  // 检查插槽内容:
  const hasFooter = slots.footer
  
  // 事件触发:
  emit('submit', payload)
  
  // 暴露公共属性:
  expose({ publicMethod })
}
        - attrs:包含未在props中声明的属性
 - slots:访问通过插槽分发的内容(v-slot语法)
 - emit:替代this.$emit的事件触发方式
 - expose:控制组件实例对外暴露的公共方法
 
(4)响应式状态管理
            
            
              javascript
              
              
            
          
          const state = reactive({
  user: {
    name: 'Alice',
    posts: []
  },
  loading: false
})
// 嵌套对象自动响应化
watchEffect(() => {
  console.log('User name changed:', state.user.name)
})
        - 深层响应性:reactive会递归转换对象属性
 - 数组处理:支持数组索引修改和length变更检测
 - 自动解包:在模板中访问ref无需.value,但JS环境中需要
 
2.2 响应式系统:重新定义数据驱动
(1)响应式核心原理
            
            
              javascript
              
              
            
          
          const targetMap = new WeakMap()
function track(target, key) {
  // 收集依赖
}
function trigger(target, key) {
  // 通知更新
}
const handler = {
  get(target, key, receiver) {
    track(target, key)
    return Reflect.get(...arguments)
  },
  set(target, key, value, receiver) {
    const result = Reflect.set(...arguments)
    trigger(target, key)
    return result
  }
}
        - Proxy代理:基于ES6 Proxy实现属性访问拦截
 - 依赖追踪:通过WeakMap建立目标对象->属性->依赖的映射关系
 - 批量更新:Vue的调度机制确保多次状态变更合并为单次更新
 
(2)ref的进阶用法
            
            
              javascript
              
              
            
          
          // DOM元素引用
const inputRef = ref<HTMLInputElement | null>(null)
// 组件挂载后访问
onMounted(() => {
  inputRef.value?.focus()
})
// 模板引用
<template>
  <input ref="inputRef">
</template>
// 复杂类型处理
const state = ref({
  user: {
    name: 'Bob'
  }
})
// 自动解包
state.value.user.name = 'Charlie'
        - 模板引用:替代this.$refs的声明方式
 - 类型标注:在TypeScript中明确指定引用类型
 - 对象嵌套:ref可以包裹复杂对象结构
 
(3)reactive的边界情况
            
            
              javascript
              
              
            
          
          // 响应式丢失场景
const state = reactive({ x: 0 })
let { x } = state // 值拷贝,失去响应性
// 正确解构方式
const { x } = toRefs(state)
// 数组处理特例
const list = reactive([1, 2, 3])
list = reactive([4,5,6]) // 错误!需要修改现有引用
list.push(4) // 正确方式
// 使用readonly保护
const protectedState = readonly(state)
protectedState.x++ // 控制台警告
        - 引用替换限制:必须保持对象引用不变
 - 数组变异方法:push/pop等标准方法可触发更新
 - 只读保护:防止意外修改共享状态
 
(4)响应式工具函数对比
| 方法 | 作用 | 典型场景 | 
|---|---|---|
| toRef | 为源响应式对象属性创建ref | props解构时保持响应性 | 
| toRefs | 转换整个响应式对象为普通对象 | 从组合函数返回响应式状态 | 
| isProxy | 检查是否为代理对象 | 调试响应式系统 | 
| isReactive | 检查reactive创建的代理 | 类型判断 | 
| isReadonly | 检查只读代理 | 安全校验 | 
| markRaw | 标记对象永不转为响应式 | 性能优化/集成第三方库 | 
| shallowRef | 创建浅层ref | 大型对象性能优化 | 
| triggerRef | 手动触发shallowRef更新 | 强制刷新界面 | 
2.3 生命周期:全新的接入方式
(1)完整生命周期映射表
| Options API | Composition API | 触发时机 | 
|---|---|---|
| beforeCreate | - | 被setup替代 | 
| created | - | 被setup替代 | 
| beforeMount | onBeforeMount | DOM挂载开始前 | 
| mounted | onMounted | DOM挂载完成后 | 
| beforeUpdate | onBeforeUpdate | 响应式数据变更导致更新前 | 
| updated | onUpdated | 虚拟DOM重新渲染后 | 
| beforeUnmount | onBeforeUnmount | 组件卸载前(vue2的beforeDestroy别名) | 
| unmounted | onUnmounted | 组件卸载后(vue2的destroyed别名) | 
| errorCaptured | onErrorCaptured | 捕获后代组件错误时 | 
| renderTracked | onRenderTracked | 响应式依赖被追踪时(开发模式) | 
| renderTriggered | onRenderTriggered | 响应式依赖触发更新时(开发模式) | 
(2)组合式生命周期示例
            
            
              javascript
              
              
            
          
          import { 
  onMounted,
  onUpdated,
  onUnmounted 
} from 'vue'
export default {
  setup() {
    // 同步调用保证正确注册
    onMounted(async () => {
      const data = await fetchData()
      // 异步操作不会阻塞生命周期
    })
    // 支持多次注册相同钩子
    onMounted(() => console.log('第一个mounted回调'))
    onMounted(() => console.log('第二个mounted回调'))
    // 清理副作用示例
    const timer = ref()
    onMounted(() => {
      timer.value = setInterval(() => {
        /* 定时任务 */
      }, 1000)
    })
    onUnmounted(() => {
      clearInterval(timer.value)
    })
  }
}
        (3)生命周期使用原则
- 
同步注册 :必须在setup同步调用生命周期钩子
javascript// 错误示例 setTimeout(() => { onMounted(() => {}) // 将不会执行 }, 100) - 
执行顺序:按照注册顺序同步执行
 - 
异步操作:钩子函数本身可以包含异步代码,但不会延迟生命周期进度
 - 
组件树顺序:父组件onBeforeMount先于子组件onBeforeMount
 
(4)调试钩子实践
            
            
              javascript
              
              
            
          
          onRenderTracked((event) => {
  console.log('依赖追踪:', event)
})
onRenderTriggered((event) => {
  console.log('依赖触发更新:', event)
})
        - 开发模式专用:帮助分析组件渲染行为
 - 事件对象:包含target(响应式对象)、key(触发属性)、type(操作类型)等信息
 - 性能优化:识别不必要的渲染触发源
 
2.4 响应式原理探秘
(1)依赖收集流程
            
            
              javascript
              
              
            
          
          // 伪代码实现
function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      track(target, key)
      return Reflect.get(target, key)
    },
    set(target, key, value) {
      const result = Reflect.set(target, key, value)
      trigger(target, key)
      return result
    }
  })
}
// 副作用函数注册
let activeEffect
class ReactiveEffect {
  constructor(fn) {
    this.fn = fn
  }
  run() {
    activeEffect = this
    return this.fn()
  }
}
function watchEffect(fn) {
  const effect = new ReactiveEffect(fn)
  effect.run()
}
        (2)响应式类型对比
| ref | reactive | shallowRef | |
|---|---|---|---|
| 创建方式 | ref(value) | reactive(object) | shallowRef(value) | 
| 访问方式 | .value | 直接访问属性 | .value | 
| 嵌套响应 | 自动展开 | 递归响应 | 非递归 | 
| 类型支持 | 基础类型/对象 | 仅对象 | 任意类型 | 
| 模板自动解包 | 支持 | 不需要 | 支持 | 
| 适用场景 | 独立基本值、模板引用 | 复杂对象结构 | 大型对象性能优化 | 
(3)响应式转换规则
            
            
              javascript
              
              
            
          
          const raw = {}
const observed = reactive(raw)
console.log(observed === raw) // false
console.log(reactive(observed) === observed) // true
const refVal = ref(0)
console.log(ref(refVal) === refVal) // true
        - 代理唯一性:对同一原始对象多次调用reactive返回相同代理
 - ref保护机制:如果传入ref给ref构造函数,直接返回原ref
 - 原始对象保护:Vue不会代理Vue实例或代理对象
 
2.5 组合式API中的上下文处理
(1)跨层级访问示例
            
            
              javascript
              
              
            
          
          // 祖先组件
import { provide } from 'vue'
setup() {
  const theme = ref('dark')
  provide('theme', theme)
}
// 后代组件
import { inject } from 'vue'
setup() {
  const theme = inject('theme', 'light') // 默认值
  return { theme }
}
        (2)模板引用转发
            
            
              javascript
              
              
            
          
          // 子组件
import { defineExpose } from 'vue'
setup() {
  const publicMethod = () => { /* ... */ }
  defineExpose({ publicMethod })
}
// 父组件
const childRef = ref()
onMounted(() => {
  childRef.value.publicMethod()
})
        三、核心API深度解析
3.1 响应式工具
            
            
              javascript
              
              
            
          
          // 解构响应式对象
import { reactive, toRefs } from 'vue'
const state = reactive({
  x: 0,
  y: 0
})
const { x, y } = toRefs(state)
        3.2 计算属性
            
            
              javascript
              
              
            
          
          const doubleCount = computed(() => count.value * 2)
        3.3 副作用管理
            
            
              javascript
              
              
            
          
          // watchEffect自动追踪依赖
const stop = watchEffect(() => {
  console.log(`count变化: ${count.value}`)
})
// 精确控制的watch
watch(count, (newVal, oldVal) => {
  // 执行特定操作
})
        四、逻辑复用模式
4.1 自定义组合函数
            
            
              javascript
              
              
            
          
          // useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
  const x = ref(0)
  const y = ref(0)
  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))
  return { x, y }
}
// 组件使用
import { useMouse } from './useMouse'
export default {
  setup() {
    const { x, y } = useMouse()
    return { x, y }
  }
}
        4.2 异步状态管理
            
            
              javascript
              
              
            
          
          // useFetch.js
import { ref } from 'vue'
export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)
  const loading = ref(false)
  async function fetchData() {
    try {
      loading.value = true
      const response = await fetch(url)
      data.value = await response.json()
    } catch (err) {
      error.value = err
    } finally {
      loading.value = false
    }
  }
  return {
    data,
    error,
    loading,
    fetchData
  }
}
        五、最佳实践
5.1 代码组织模式
            
            
              javascript
              
              
            
          
          export default {
  setup() {
    // 数据逻辑
    const { x, y } = useMouse()
    
    // 业务逻辑
    const { data, fetch } = useFetch('/api')
    
    // 其他逻辑
    const count = useCounter()
    return { x, y, data, fetch, count }
  }
}
        5.2 TypeScript集成
            
            
              typescript
              
              
            
          
          interface User {
  id: number
  name: string
}
const users = ref<User[]>([])
        六、与Options API对比
6.1 逻辑组织对比
            
            
              javascript
              
              
            
          
          // Options API
export default {
  data() {
    return { count: 0 }
  },
  methods: {
    increment() { this.count++ }
  },
  mounted() {
    console.log('挂载完成')
  }
}
// Composition API
export default {
  setup() {
    const count = ref(0)
    const increment = () => count.value++
    onMounted(() => console.log('挂载完成'))
    return { count, increment }
  }
}