恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Vue 2 / Vue 3 与响应式核心知识整合

  • 首页
  • 资讯中心
  • /
  • Vue 2 / Vue 3 与响应式核心知识整合

相关资讯

Mavericks 项目中的 View Binding 实践:用一行 `by viewBinding()` 替代 findViewById 2026/10/10 2:44:55
海外SaaS应用加速部署(进阶篇):从入门到实战完整指南 2026/10/10 2:44:55
2026年育婴师培训价格标准明细与行业现状分析 2026/10/10 2:44:55

最新资讯

Windows权限提升实战指南:从令牌到服务的提权命令详解
Windows硬件四层验证法:dxdiag/msinfo32/设备管理器/PowerShell交叉诊断
Windows权限提升防御实战:原理、排查命令与日志监控指南
小型MIS开发实战:从数据库设计到JDBC事务控制的完整拆解
从杀软盲区到行为检测:一份防御视角的免杀对抗笔记
告别日志一锅粥:Rider分窗查看Console与Debug输出全攻略

今日推荐

Codex 总用英文回答?从 AGENTS.md 到 config.toml 的中文输出调优指南
OpenClaw 自定义插件开发完整指南(2026最新版):从 TypeScript 到 npm 发布
基于Spark的电影推荐系统全链路实战:从爬虫到Web展示

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Vue 2 / Vue 3 与响应式核心知识整合

发布时间:2026/10/10 2:44:55
Vue 2 / Vue 3 与响应式核心知识整合 文章目录一、Vue 2 与 Vue 3 的主要差异核心架构API 风格生命周期变化其他重要变化注意点二、响应式差异简单易懂版一句话总结Vue 2 的问题Vue 3 的解决记忆口诀三、Vue 3 的懒代理机制含义对比为什么更快注意点记忆口诀四、reactive 和 ref 的区别一句话总结基本用法核心区别对照表注意点怎么选记忆口诀五、为什么 reactive 解构丢响应式ref 不丢前提JS 赋值传的是值或引用reactive 的响应式挂在哪里ref 为什么通常不丢核心对比一句话reactive 想解构保持响应式用 toRefs记忆口诀六、RefImpl 实例是什么是什么为什么需要这个壳{ value: 0 } 是什么意思ref 装对象时记忆口诀七、reactive 嵌套对象解构会出错吗怎么解决结论数据解构第一层解构第二层一定丢解决办法总结表记忆口诀实战建议一、Vue 2 与 Vue 3 的主要差异核心架构维度Vue 2Vue 3响应式原理Object.definePropertyProxyAPI 风格Options API 为主Composition API Options API源码语言JavaScriptTypeScript 重写虚拟 DOM全量 diff编译时优化 Patch Flag打包体积runtime ~23KBruntime ~10KBgzip核心差异是响应式Vue 2 用defineProperty递归劫持属性无法检测新增/删除属性、数组下标赋值需Vue.set/$set。Vue 3 用Proxy代理整个对象任意增删改查都能拦截支持Map/Set。API 风格// Vue 2 Options APIexportdefault{data(){return{count:0}},methods:{inc(){this.count}}}// Vue 3 Composition APIimport{ref}fromvueconstcountref(0)constinc()count.value生命周期变化beforeDestroy→beforeUnmountdestroyed→unmountedComposition API 中用onMounted、onUnmounted等。其他重要变化多根节点Vue 3 支持 Fragment模板不再必须单根。新增Teleport、Suspense。v-model支持多个默认 prop 从value改为modelValue。移除filter、$on/$off/$once。全局 APIVue.use()→createApp().use()避免全局污染。异步组件用defineAsyncComponent。注意点Vue 2 已于2023 年 12 月 31 日 EOL新项目直接用 Vue 3。老项目迁移可用vue/compat渐进过渡。二、响应式差异简单易懂版一句话总结Vue 2提前登记每个属性漏登记的发现不了。Vue 3整体代理任何风吹草动都逃不掉。Vue 2 的问题用Object.defineProperty在初始化时递归给每个属性装 getter/setter。this.user.age18// ❌ 新增属性视图不更新deletethis.user.name// ❌ 删除属性视图不更新this.list[0]new// ❌ 数组下标赋值不更新this.list.length0// ❌ 改长度不更新必须用$set/$delete数组靠重写push/pop/splice打补丁。初始化时递归所有层级性能差。Vue 3 的解决用Proxy包住整个对象天然拦截增删改查。constdatareactive({user:{name:Tom}})data.user.age18// ✅deletedata.user.name// ✅data.list[0]new// ✅操作Vue 2Vue 3改已有属性✅✅新增属性❌ 需 $set✅删除属性❌ 需 $delete✅数组下标赋值❌✅Map / Set❌✅记忆口诀Vue 2 靠提前登记每个属性漏登记的发现不了Vue 3 靠整体代理任何变化都逃不掉。三、Vue 3 的懒代理机制含义Vue 3 初始化时只代理最外层对象访问到哪层才代理哪层。constdatareactive({user:{name:Tom,address:{city:Beijing}}})// 此刻只代理 data 这一层data.user// 触发 get → 给 user 包上 Proxydata.user.address// 再触发 → 给 address 包上 Proxydata.user.address.city// 用到哪层代理到哪层如果从没访问过data.user它内部永远不会被代理。对比数据{ a: { b: { c: { d: 1 } } } }阶段Vue 2Vue 3初始化递归到 d全部装监听只代理最外层 a访问a.b已就绪此时才代理 b从没访问a.b.c照样装监听浪费完全没代理省了为什么更快初始化不用递归启动快。按需代理用不到的分支零开销。内存更省未访问对象不产生 Proxy 包装。注意点懒代理不影响响应式正确性。访问过的层之后修改照样触发更新。它只是把装监听从初始化推迟到首次访问是性能优化不是功能缺失。记忆口诀Vue 2进门先把整栋楼每个房间都装好监控。Vue 3走到哪个房间才给哪个房间装监控。四、reactive 和 ref 的区别一句话总结reactive只能代理对象ref可以装任何类型用的时候要.value。基本用法// reactive只能传对象/数组/Map/Setconststatereactive({count:0})state.count// 直接改// ref任意类型constcountref(0)count.value// 要 .value核心区别对照表维度reactiveref接受类型只能对象/数组等任意类型访问方式直接state.count要count.value模板中直接state.count自动解包写count底层实现ProxyRefImpl类getter/setter解构后丢失响应式解构出 ref 对象不丢整体替换不能直接替换可以count.value 新值注意点只有模板里 ref 自动解包script里必须写.value。reactive 解构会丢响应式需用toRefs。reactive 不能整体替换state reactive({...})会切断连接。ref 装对象时内部用 reactive 实现user.value.name x是响应式的。怎么选优先用ref什么都能装解构/替换安全坑少。用reactive的场景一组相关状态组成对象如表单且不会整体替换、不会解构。constformreactive({username:,password:})记忆口诀ref万能但要.value模板里帮你省掉。reactive只管对象直接访问但别解构、别整体替换。五、为什么 reactive 解构丢响应式ref 不丢前提JS 赋值传的是值或引用conststatereactive({count:0})let{count}state// 等价于 let count state.count// state.count 是数字 0基本类型复制一份值count// 只改副本跟 state.count 无关reactive 的响应式挂在哪里reactive(obj)返回Proxy响应式能力在 Proxy 对象上state.count读 → 走 Proxyget收集依赖。state.count 1写 → 走 Proxyset触发更新。但state.count本身只是一个裸数字。解构出来拿到的就是数字Proxy 没参与Vue 无从追踪。ref 为什么通常不丢ref(0)返回的不是数字而是包装对象{ value: 0 }响应式在value的 getter/setter 上。constcountref(0)count.value// 走 getter收集依赖count.value1// 走 setter触发更新注意解构.value一样会丢let{value}count value// ❌ 只改本地变量count.value// 还是 0常说的ref 解构不丢是因为通常解构的是ref 对象本身const{count}useSomething()// count 仍是 ref 对象count.value// ✅ 响应式核心对比reactiveref响应式载体Proxy 对象{ value }包装对象解构出值state.count→ 数字丢count.value→ 数字也丢解构出对象本身不存在此操作const { count } ...→ ref 对象不丢一句话reactive 解构拿到的是值值没有响应式能力丢。ref 解构拿到的通常是包装对象本身自带响应式不丢。reactive 想解构保持响应式用toRefsconst{count,name}toRefs(state)// 每个属性变成 refcount.value// ✅toRefs的本质不复制值创建指向原属性的 ref读写.value转发到原对象。记忆口诀JS 赋值传的是值或引用。reactive 的响应式在 Proxy 壳上属性是裸值解构就断链。ref 的响应式在{ value }壳上解构出壳还在解构出.value一样断。toRefs就是给 reactive 的每个属性补一个壳。六、RefImpl 实例是什么是什么RefImpl是 Vue 3 源码里的一个类Ref Implementation。ref(0)返回的是new RefImpl(0)一个实例对象不是数字 0。源码简化classRefImpl{public_valuepublicdepnewSet()constructor(value){this._valuevalue}getvalue(){track(this,value)// 收集依赖returnthis._value}setvalue(newVal){if(newVal!this._value){this._valuenewValtrigger(this,value)// 触发更新}}}为什么需要这个壳基本类型数字、字符串没法加 getter/setterVue 无法拦截读写。所以 Vue 把值藏在一个对象里在对象的value属性上做手脚constcountref(0)// RefImpl 实例count.value// 读 → getter → 收集依赖count.value1// 写 → setter → 触发更新{ value: 0 }是什么意思这是简化的说法方便理解有一个 value 属性、值为 0 的对象。真实的 RefImpl 实例控制台打印RefImpl { __v_isRef: true, dep: undefined, _value: 0, _rawValue: 0 }它不是字面量{ value: 0 }而是真正的值存在_value。value是定义在类上的 getter/setter。依赖存在dep。{ value: 0 }只是对对外接口的简化描述。ref 装对象时内部用reactive再包一层constuserref({name:Tom})// 内部this._value reactive({ name: Tom })user.value.nameJerry// ✅ 响应式基本类型靠 RefImpl 的valuegetter/setter。对象类型靠reactive的 Proxy。记忆口诀ref(0)返回的是 RefImpl 实例对象不是数字 0。它用 get/set 定义value把真值藏在_value从而能拦截读写实现响应式。{ value: 0 }只是对外接口的简化描述。七、reactive 嵌套对象解构会出错吗怎么解决结论解构不会报错但会丢响应式。嵌套对象解构出来同样是丢。解决用toRefs/toRef。数据conststatereactive({count:0,user:{name:Tom,age:18}})解构第一层const{count,user}statecount→ 数字丢。user→ Proxy 引用暂时不丢user.name x仍响应式。但注意如果state.user被整体替换user就与state.user脱节state.user{name:Jerry,age:20}user.name// 还是旧对象的值 ❌解构第二层一定丢const{name}state.user// name 是字符串裸值nameJerry// ❌ 只改本地变量只要解构到基本类型的值就丢。解决办法方法 1toRefs处理第一层const{count,user}toRefs(state)count.value// ✅user.value.nameJerry// ✅注意toRefs只处理第一层。方法 2toRef针对单个属性constusertoRef(state,user)user.value.nameJerry// ✅本质创建转发到原对象的 ref即使原属性被整体替换.value也能拿到新值。方法 3嵌套逐层toRefsconst{count,user}toRefs(state)const{name,age}toRefs(user.value)name.valueJerry// ✅方法 4干脆不解构state.user.nameJerry// ✅ 一直走 Proxy方法 5深层数据单独用refconstuserref({name:Tom,age:18})user.value{name:Jerry,age:20}// ✅ 整体替换没问题总结表操作是否丢原因const { count } state数字❌ 丢拿到裸值const { user } state对象⚠️ 暂时不丢整体替换后丢拿到 Proxy 引用会脱节const { name } state.user字符串❌ 丢拿到裸值toRefs(state)后解构✅ 不丢属性变 reftoRef(state, user)✅ 不丢创建转发 ref不解构state.user.name✅ 不丢一直走 Proxy记忆口诀解构到值基本类型→ 必丢。解构到对象引用→ 暂时在原对象被整体替换就断。想安全第一层用toRefs单个用toRef嵌套逐层toRefs或干脆别解构。实战建议嵌套较深、又需要解构时优先把深层数据单独用ref抽出来比一层层toRefs更清晰。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号