Skip to content

Vue 版本演进:Vue 2 与 Vue 3 全对比

接手维护一个老项目,进去一看 package.json 里躺着 vue: ^2.6.14;自己新起的项目用的却是 Vue 3。两套代码摆在一起,写法完全两个时代:老项目里 data/methods/computed 分家、新增属性还要 Vue.set;新项目一个 setup() 全搞定、reactive 随手加属性就响应。

明明都叫 Vue,为什么差别这么大?因为中间隔了一次内核级重写。这篇把 Vue 的版本演进和 Vue 2 → Vue 3 的差异系统梳理一遍,看完你就能回答:为什么会有 Vue 3、老项目要不要升、新项目怎么选。

版本时间线:三个时代

Vue 版本演进

版本时间定位
Vue 1.x2014初版,模板引擎 + 数据绑定,小步试水
Vue 2.x2016–2023统治前端近十年,官方最后版本 2.7.16(2022 年发布)
Vue 3.x2020–至今内核全面重写,当前唯一活跃主线(3.5+)

关键时间点:Vue 2.7(2022)是 2.x 的终点,官方把组合式 API 回迁到 2.7 里当「兼容桥」,让大家在升级到 3 之前就能用新写法;Vue 2 官方支持已于 2023 年底停止。

Vue 2 的三大硬伤:为什么必须重写

Vue 3 不是小修小补,是推倒重来。Vue 2 有三个被吐槽最多的根子上的问题:

  1. 响应式天花板:基于 Object.defineProperty,只能拦截「已存在的属性」。新增属性、删除属性、数组按索引赋值全都不响应——于是被迫发明 Vue.set / $delete / splice 一堆补丁 API,且每次操作还得递归遍历,深层对象性能开销大。
  2. 逻辑复用靠 mixin:多个组件共用一段逻辑,只能 mixin 进去,命名冲突、来源不明,代码一多就乱。
  3. TypeScript 支持弱:Vue 2 源码是 JS 写的,类型全靠社区补丁(vue-class-component / vue-property-decorator),体验远不如人意。

这三个问题正是 Vue 3 设计时重点解决的。下面看差异到底有多大。

Vue 2 vs Vue 3:核心差异对照表

维度Vue 2Vue 3
响应式原理Object.defineProperty 逐个拦截已有属性Proxy 对象级代理,全量拦截
新增/删除属性❌ 不响应,必须 Vue.set / $delete✅ 直接响应
数组变更重写 7 个变异方法,索引赋值不响应✅ 索引赋值、length 修改全响应
编写 APIOptions API(data/methods/computed 分家)Composition API(setup 内按逻辑组织)
逻辑复用mixin(命名冲突、来源不明)composable(纯函数,天然隔离)
TypeScript支持弱,靠社区补丁源码 TS 重写,一等公民
官方状态库VuexPinia(Vuex 5 前身)
Vue Router3.x4.x(API 基本兼容)
虚拟 DOM传统 diff重写:patchFlag、静态提升、事件缓存
包体积完整版约 30KB+tree-shaking 支持,按需约减半
多根节点❌ 组件必须单根✅ Fragment,支持多根
全局 APIVue.xxx(Vue.use / Vue.component)app.xxx(createApp 实例化)

上面「响应式」两行的差异是实跑验证过的(vue 2.7.16 与 @vue/reactivity 3.x,Node 实跑 9 断言全 PASS):

js
// Vue 2:新增属性不响应,必须 Vue.set
const obj = Vue.observable({ count: 1 });
obj.newKey = 42;          // 无 getter/setter,改了视图不更新
Vue.set(obj, 'newKey', 42); // 正确姿势

// Vue 3:reactive 后新增/删除属性直接响应
const obj = reactive({ count: 1 });
obj.newKey = 42;   // 直接生效
delete obj.count;  // 也会触发更新

definePropertyProxy 的机制细节,见《Vue 响应式原理详解》——那里用 12 个断言实跑演示了「为什么 Vue 2 要 $set、Vue 3 不用」。

破坏性变更:升级到 Vue 3 要改什么

升级不是平滑的,下面是迁移时最容易踩的几处:

变更点Vue 2Vue 3
全局 APIVue.use(VueRouter)app.use(router),全局 API 移到应用实例
事件总线$on / $off / $emit 全局事件移除,改用 mitt 等第三方库
filtersprice | currency 模板过滤器(Vue 2 独有)移除,改函数或 computed
v-model组件上 value + inputmodelValue + update:modelValue,支持多个 v-model
自定义指令钩子bind / inserted / updatebeforeMount / mounted / updated 统一对齐生命周期
异步组件Vue.component('x', () => import(...))defineAsyncComponent
插槽语法具名插槽 slot="name"v-slot 统一(简写 #name
this 指向Options 里 this 指向组件实例setup 里没有 this,用 ref/reactive 替代

最伤的是 filters 移除$on/$off 移除——老项目里这两个用得越狠,迁移成本越高,这也是很多团队选择「老项目停在 2.7」的原因。

怎么选:新项目 / 老项目

  • 新项目:无脑 Vue 3。官方只维护 3.x,配套 Vite 开发体验、Pinia、组合式 API 生态全在新版,没有任何理由回头。
  • 老项目在 Vue 2 且没到 2.7:先升到 2.7(成本低,无破坏性变更),拿到组合式 API 和更好的 TS 支持,用新写法逐步重构,为将来升 3 铺路。
  • 老项目在 2.7 且业务稳定:可以不升 3——但要知道 2.7 已停止官方支持,依赖的安全漏洞要靠自己兜底。
  • 真要升 3:用官方迁移构建版本 + 迁移工具逐步处理破坏性变更,组件逐个迁移,别一次推倒。

Composition API 的写法和 mixin → composable 的演进,见《Vue Composition API 详解》;Vue 3 的模板语法、组件化怎么上手,看《Vue 快速入门》;组件之间怎么通信,看《Vue 组件通信全景》。