深入探索Vue 3组合式API

深入探索Vue 3组合式API

  • 深入探索Vue 3组合式API
    • 一、组合式API诞生背景
      • 1.1 Options API的局限性
      • 1.2 设计目标
      • 二、核心概念解析
        • 2.1 setup() 函数:组合式API的基石
        • 2.2 响应式系统:重新定义数据驱动
        • 2.3 生命周期:全新的接入方式
        • 2.4 响应式原理探秘
        • 2.5 组合式API中的上下文处理
    • 三、核心API深度解析
      • 3.1 响应式工具
      • 3.2 计算属性
      • 3.3 副作用管理
    • 四、逻辑复用模式
      • 4.1 自定义组合函数
      • 4.2 异步状态管理
    • 五、最佳实践
      • 5.1 代码组织模式
      • 5.2 TypeScript集成
    • 六、与Options API对比
      • 6.1 逻辑组织对比

深入探索Vue 3组合式API

一、组合式API诞生背景

1.1 Options API的局限性

  • 代码组织碎片化
  • 逻辑复用困难(mixins缺陷)
  • 类型支持不足

1.2 设计目标

  • 更好的逻辑复用
  • 更灵活的组织方式
  • 更好的类型推导
  • 渐进式采用策略

二、核心概念解析

2.1 setup() 函数:组合式API的基石

(1)函数特性与执行时机

export default {setup(props, context) {// 在beforeCreate之前执行// 无法访问this// 返回对象将暴露给模板和其他选项}
}
  • 执行顺序:在组件实例创建之前同步执行,位于beforeCreatecreated生命周期之间
  • 参数解析
    • props:响应式的props对象,结构会失去响应性
    • context:包含attrs、slots、emit的非响应式对象
  • 返回值
    • 返回对象属性将合并到模板渲染上下文
    • 可返回渲染函数直接控制视图输出

(2)props处理规范

import { defineComponent } from 'vue'interface Props {title: stringcount?: 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)上下文对象解析

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)响应式状态管理

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)响应式核心原理

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的进阶用法

// 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的边界情况

// 响应式丢失场景
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为源响应式对象属性创建refprops解构时保持响应性
toRefs转换整个响应式对象为普通对象从组合函数返回响应式状态
isProxy检查是否为代理对象调试响应式系统
isReactive检查reactive创建的代理类型判断
isReadonly检查只读代理安全校验
markRaw标记对象永不转为响应式性能优化/集成第三方库
shallowRef创建浅层ref大型对象性能优化
triggerRef手动触发shallowRef更新强制刷新界面

2.3 生命周期:全新的接入方式

(1)完整生命周期映射表

Options APIComposition API触发时机
beforeCreate-被setup替代
created-被setup替代
beforeMountonBeforeMountDOM挂载开始前
mountedonMountedDOM挂载完成后
beforeUpdateonBeforeUpdate响应式数据变更导致更新前
updatedonUpdated虚拟DOM重新渲染后
beforeUnmountonBeforeUnmount组件卸载前(vue2的beforeDestroy别名)
unmountedonUnmounted组件卸载后(vue2的destroyed别名)
errorCapturedonErrorCaptured捕获后代组件错误时
renderTrackedonRenderTracked响应式依赖被追踪时(开发模式)
renderTriggeredonRenderTriggered响应式依赖触发更新时(开发模式)

(2)组合式生命周期示例

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)生命周期使用原则

  1. 同步注册:必须在setup同步调用生命周期钩子
    // 错误示例
    setTimeout(() => {onMounted(() => {}) // 将不会执行
    }, 100)
    
  2. 执行顺序:按照注册顺序同步执行
  3. 异步操作:钩子函数本身可以包含异步代码,但不会延迟生命周期进度
  4. 组件树顺序:父组件onBeforeMount先于子组件onBeforeMount

(4)调试钩子实践

onRenderTracked((event) => {console.log('依赖追踪:', event)
})onRenderTriggered((event) => {console.log('依赖触发更新:', event)
})
  • 开发模式专用:帮助分析组件渲染行为
  • 事件对象:包含target(响应式对象)、key(触发属性)、type(操作类型)等信息
  • 性能优化:识别不必要的渲染触发源

2.4 响应式原理探秘

(1)依赖收集流程

// 伪代码实现
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 = thisreturn this.fn()}
}function watchEffect(fn) {const effect = new ReactiveEffect(fn)effect.run()
}

(2)响应式类型对比

refreactiveshallowRef
创建方式ref(value)reactive(object)shallowRef(value)
访问方式.value直接访问属性.value
嵌套响应自动展开递归响应非递归
类型支持基础类型/对象仅对象任意类型
模板自动解包支持不需要支持
适用场景独立基本值、模板引用复杂对象结构大型对象性能优化

(3)响应式转换规则

const raw = {}
const observed = reactive(raw)console.log(observed === raw) // false
console.log(reactive(observed) === observed) // trueconst refVal = ref(0)
console.log(ref(refVal) === refVal) // true
  • 代理唯一性:对同一原始对象多次调用reactive返回相同代理
  • ref保护机制:如果传入ref给ref构造函数,直接返回原ref
  • 原始对象保护:Vue不会代理Vue实例或代理对象

2.5 组合式API中的上下文处理

(1)跨层级访问示例

// 祖先组件
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)模板引用转发

// 子组件
import { defineExpose } from 'vue'setup() {const publicMethod = () => { /* ... */ }defineExpose({ publicMethod })
}// 父组件
const childRef = ref()onMounted(() => {childRef.value.publicMethod()
})

三、核心API深度解析

3.1 响应式工具

// 解构响应式对象
import { reactive, toRefs } from 'vue'const state = reactive({x: 0,y: 0
})const { x, y } = toRefs(state)

3.2 计算属性

const doubleCount = computed(() => count.value * 2)

3.3 副作用管理

// watchEffect自动追踪依赖
const stop = watchEffect(() => {console.log(`count变化: ${count.value}`)
})// 精确控制的watch
watch(count, (newVal, oldVal) => {// 执行特定操作
})

四、逻辑复用模式

4.1 自定义组合函数

// 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.pageXy.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 异步状态管理

// 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 = trueconst 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 代码组织模式

export default {setup() {// 数据逻辑const { x, y } = useMouse()// 业务逻辑const { data, fetch } = useFetch('/api')// 其他逻辑const count = useCounter()return { x, y, data, fetch, count }}
}

5.2 TypeScript集成

interface User {id: numbername: string
}const users = ref<User[]>([])

六、与Options API对比

6.1 逻辑组织对比

// 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 }}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/70124.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微调llama3问题解决-RuntimeError: CUDA unknown error - this may be due to an incorrectly set up environment

问题说明之一 具体问题如下&#xff1a; RuntimeError: CUDA unknown error - this may be due to an incorrectly set up environment, e.g. changing env variable CUDA_VISIBLE_DEVICES after program start. Setting the available devices to be zero.我使用的这套是根据…

Redis代金卷(优惠卷)秒杀案例-单应用版

优惠卷表:优惠卷基本信息,优惠金额,使用规则 包含普通优惠卷和特价优惠卷(秒杀卷) 优惠卷的库存表:优惠卷的库存,开始抢购时间,结束抢购时间.只有特价优惠卷(秒杀卷)才需要填写这些信息 优惠卷订单表 卷的表里已经有一条普通优惠卷记录 下面首先新增一条秒杀优惠卷记录 { &quo…

Notepad++消除生成bak文件

设置(T) ⇒ 首选项... ⇒ 备份 ⇒ 勾选 "禁用" 勾选禁用 就不会再生成bak文件了 notepad怎么修改字符集编码格式为gbk 如图所示

物联网领域的MQTT协议,优势和应用场景

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为轻量级发布/订阅协议&#xff0c;凭借其低带宽消耗、低功耗与高扩展性&#xff0c;已成为物联网通信的事实标准。其核心优势包括&#xff1a;基于TCP/IP的异步通信机制、支持QoS&#xff08;服务质量&…

Node.js与嵌入式开发:打破界限的创新结合

文章目录 一、Node.js的本质与核心优势1.1 什么是Node.js&#xff1f;1.2 嵌入式开发的范式转变 二、Node.js与嵌入式结合的四大技术路径2.1 硬件交互层2.2 物联网协议栈2.3 边缘计算架构2.4 轻量化运行时方案 三、实战案例&#xff1a;智能农业监测系统3.1 硬件配置3.2 软件架…

【物联网】ARM核常用指令(详解):数据传送、计算、位运算、比较、跳转、内存访问、CPSR/SPSR

文章目录 指令格式&#xff08;重点&#xff09;1. 立即数2. 寄存器位移 一、数据传送指令1. MOV指令2. MVN指令3. LDR指令 二、数据计算指令1. ADD指令1. SUB指令1. MUL指令 三、位运算指令1. AND指令2. ORR指令3. EOR指令4. BIC指令 四、比较指令五、跳转指令1. B/BL指令2. l…

Redis基础(二)——通用命令与五大基本数据类型

目录 一、Redis数据结构基本介绍 二、Redis通用命令 1.查看通用命令 2.KEYS&#xff1a;查看符合模板的所有key 3.DEL&#xff1a;删除指定的Key 4.lEXISTS&#xff1a;判断key是否存在 5.lEXPIRE&#xff1a;给一个key设置有效期&#xff0c;有效期到期时该key会被自…

ComfyUI工作流 参考图像生成人像手办(SDXL版)

文章目录 参考图像生成人像手办SD模型Node节点工作流程效果展示开发与应用参考图像生成人像手办 此工作流旨在实现将图像生成高精度的3D手办风格效果,通过深度学习技术完成从图像处理、模型加载、提示词优化到图像生成和超分辨率处理的一系列操作。整个流程以SDXL模型为核心,…

c语言 程序计算圆的面积(Program to find area of a circle)

给定圆的半径&#xff0c;求该圆的面积。 可以使用以下公式简单地计算圆的面积。 其中 r 是圆的半径&#xff0c;它可能是浮点数&#xff0c;因为饼图的值为 3.14 方法&#xff1a;使用给定的半径&#xff0c;使用上述公式找到面积&#xff1a;&#xff08;pi * r * r&#…

解析PHP文件路径相关常量

PHP文件路径相关常量包括以下几个常量&#xff1a; __FILE__&#xff1a;表示当前文件的绝对路径&#xff0c;包括文件名。 __DIR__&#xff1a;表示当前文件所在的目录的绝对路径&#xff0c;不包括文件名。 dirname(__FILE__)&#xff1a;等同于__DIR__&#xff0c;表示当前…

蓝桥杯C语言组:暴力破解

基于C语言的暴力破解方法详解 暴力破解是一种通过穷举所有可能的解来找到正确答案的算法思想。在C语言中&#xff0c;暴力破解通常用于解决那些问题规模较小、解的范围有限的问题。虽然暴力破解的效率通常较低&#xff0c;但它是一种简单直接的方法&#xff0c;适用于一些简单…

基于STM32的智能安防监控系统

1. 引言 随着物联网技术的普及&#xff0c;智能安防系统在家庭与工业场景中的应用日益广泛。本文设计了一款基于STM32的智能安防监控系统&#xff0c;集成人体感应、环境异常检测、图像识别与云端联动功能&#xff0c;支持实时报警、远程监控与数据回溯。该系统采用边缘计算与…

【Linux系统】CPU指令集 和 Linux系统权限 ring 0 / ring 3

CPU 指令集 CPU 指令集&#xff1a;是 CPU 实现软件指挥硬件执行的媒介&#xff0c;具体来说每一条汇编语句都对应了一条CPU指令&#xff0c;而非常非常多的 CPU 指令在一起&#xff0c;可以组成一个、甚至多个集合&#xff0c;指令的集合叫CPU指令集。 CPU 指令集有权限分级&…

Slint的学习

Slint是什么 Slint是一个跨平台的UI工具包&#xff0c;支持windows,linux,android,ios,web&#xff0c;可以用它来构建申明式UI,后端代码支持rust,c,python,nodejs等语言。 开源地址&#xff1a;https://github.com/slint-ui/slint 镜像地址&#xff1a;https://kkgithub.com/…

互联网行业常用12个数据分析指标和八大模型

本文目录 前言 一、互联网线上业务数据分析的12个指标 1. 用户数据&#xff08;4个&#xff09; (1) 存量&#xff08;DAU/MAU&#xff09; (2) 新增用户 (3) 健康程度&#xff08;留存率&#xff09; (4) 渠道来源 2. 用户行为数据&#xff08;4个&#xff09; (1) 次数/频率…

九. Redis 持久化-RDB(详细讲解说明,一个配置一个说明分析,步步讲解到位)

九. Redis 持久化-RDB(详细讲解说明&#xff0c;一个配置一个说明分析&#xff0c;步步讲解到位) 文章目录 九. Redis 持久化-RDB(详细讲解说明&#xff0c;一个配置一个说明分析&#xff0c;步步讲解到位)1. RDB 概述2. RDB 持久化执行流程3. RDB 的详细配置4. RDB 备份&恢…

[权限提升] Windows 提权 维持 — 系统错误配置提权 - Trusted Service Paths 提权

关注这个专栏的其他相关笔记&#xff1a;[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01&#xff1a;Trusted Service Paths 提权原理 Windows 的服务通常都是以 System 权限运行的&#xff0c;所以系统在解析服务的可执行文件路径中的空格的时候也会以 System 权限进行解析&a…

通信易懂唠唠SOME/IP——SOME/IP-SD服务发现阶段和应答行为

一 SOME/IP-SD服务发现阶划分 服务发现应该包含3个阶段 1.1 Initial Wait Phase初始等待阶段 初始等待阶段的作用 初始等待阶段是服务发现过程中的一个阶段。在这个阶段&#xff0c;服务发现模块等待服务实例的相关条件满足&#xff0c;以便继续后续的发现和注册过程。 对…

【python】python基于机器学习与数据分析的手机特性关联与分类预测(源码+数据集)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 python基于机器学习与数据分析的手机特性关联与分类…

测试csdn图片发布

测试csdn图片发布 ​​