前言
从 Vue 2 到 Vue 3,不仅仅是版本的跳跃,更是底层思想的革新。从 Object.defineProperty 到 Proxy,从 Options API 到 Composition API,Vue 3 在性能和开发体验上都实现了质的飞跃。本文将带你系统梳理两者的核心区别。
一、 响应式原理:从“属性拦截”到“对象代理”
响应式系统的升级是 Vue 3 性能提升的关键。
1. Vue 2:Object.defineProperty
-
原理:初始化时通过递归遍历
data,为每个属性设置getter和setter。 -
局限性:
- 无法检测到对象属性的新增和删除。
- 无法直接监听数组索引的变化和
length属性。 - 必须使用
this.$set等特有 API 来弥补。 - 递归过程在处理大数据量时存在性能瓶颈。
2. Vue 3:ES6 Proxy
-
原理:直接监听整个代理对象,拦截所有操作(如
get,set,deleteProperty,has等)。 -
优势:
- 原生支持:自动支持动态增删属性、数组下标修改。
- 懒代理(Lazy Tracking) :只有当访问到深层属性时,才会动态将其转为响应式,大大提升了初始化速度。
- 性能更好:省去了初始化时繁琐的递归遍历。
二、 编写模式:从“碎片化”到“模块化”
代码组织方式的改变直接影响了大型项目的维护成本。
1. Vue 2:选项式 API (Options API)
- 痛点:逻辑被强行拆分在
data、methods、computed等固定选项中。当一个组件功能复杂时,同一个功能的代码会散落在各处,导致开发者反复上下滚动查找,难以维护。
2. Vue 3:组合式 API (Composition API)
-
优势:通过
<script setup>,开发者可以按照功能逻辑将代码组织在一起。 -
逻辑复用:可以轻松地将逻辑抽离成独立的
useHooks函数,解决了 Vue 2 中mixin命名冲突和来源不明的问题。
三、 Vue 3 核心新特性与语法糖
1. 响应式新成员:ref vs reactive
- ref:万能型。支持基本类型和引用类型,通过
.value访问(模板中自动解包)。 - reactive:对象型。仅支持引用类型,直接操作属性,无需
.value。
2. defineModel:双向绑定的“减法”
在 Vue 3.4+ 中引入的 defineModel 极大地简化了父子组件通信:
- Vue 2 做法:需要
props接收值 +this.$emit('update:xxx')触发更新。 - Vue 3 新语法:子组件直接使用
const model = defineModel(),修改model的值会自动同步到父组件,代码量骤减。
3. 多根节点模板
- Vue 2:模板内必须有一个唯一的根节点(通常是
<div>),否则报错。 - Vue 3:原生支持多个根节点,减少了不必要的 DOM 层级,使 HTML 结构更简洁。
4. 异步处理神器:<Suspense>
- 新增内置组件,专门用于处理异步组件的加载状态。它提供了
default和fallback两个插槽,可以优雅地展示“加载中”和“加载完成”的 UI 切换。
四、 总结:为什么要升 Vue 3?
| 类别 | Vue2 | Vue3 |
|---|---|---|
| 响应式原理 | Object.defineProperty 逐个属性劫持 | Proxy 代理整个对象,懒加载 |
| 编写模式 | 选项式API(Options API) | 组合式API(Composition API + |
| 模板规范 | 仅支持单个根节点 | 支持多个根节点 |
| 数据监听 | 无法监听对象增删、数组索引 | 原生支持对象增删、数组下标修改 |
| 组件双向绑定 | props + emit 手动实现 | defineModel 语法糖简化 |
| 异步加载 | 手动处理加载状态 | 内置 Suspense 组件 |