1、Vue3 前世今生:为什么要有 Vue3?Vue2 的痛点与 Vue3 的破局

1.1 从 Vue2 到 Vue3:一场不得不做的升级

说实话,Vue2 已经足够优秀了。我在 2016 年第一次接触它时,就被它的简洁和易用性打动了。但随着时间的推移,尤其是当我开始接手一些大型项目后,Vue2 的一些「老毛病」逐渐暴露了出来。

为什么会这样?因为前端生态发展太快了。TypeScript 成了标配,组件库越来越庞大,页面逻辑越来越复杂。Vue2 的设计理念,说白了还是「小项目思维」—— 它更适合中小型应用,一旦规模上去,各种问题就来了。

我记得有一次,我负责一个包含 200+ 组件的后台管理系统。光是维护 mixin 之间的数据流,就让我头疼了好几天。嗯,那时候我就意识到,Vue2 的「舒适区」已经不够用了。

1.2 Vue2 的四大痛点

咱们来细数一下 Vue2 在实际项目中让我「抓狂」的地方。你想想看,是不是也遇到过类似的问题?

痛点一:TypeScript 支持太「勉强」

Vue2 对 TypeScript 的支持,说白了就是「硬凑」。你用 vue-class-component 写起来别扭,用 Options API 又没法很好地推导类型。我在项目中试过几次,最后都放弃了 —— 类型检查形同虚设,还不如纯 JS 来得痛快。

典型场景: 一个复杂的表单组件,props 类型定义需要写一堆装饰器,而且 IDE 的智能提示经常「罢工」。

痛点二:逻辑复用全靠「骚操作」

Vue2 的逻辑复用,无非就是 mixin、高阶组件、作用域插槽这三板斧。但说实话,每个都有坑:

  • mixin:命名冲突、数据来源不明确。我曾经排查过一个 bug,两个 mixin 都定义了 handleClick 方法,结果后加载的覆盖了前面的 —— 调试了整整一下午。
  • 高阶组件:层层嵌套,props 传递像「俄罗斯套娃」,维护起来想哭。
  • 作用域插槽:模板里写一堆 v-slot,可读性极差。

痛点三:响应式系统的「天花板」

Vue2 的响应式基于 Object.defineProperty,这个 API 有个硬伤 —— 它无法监听数组下标的变化,也无法监听对象属性的新增和删除。所以 Vue2 才搞出了 $set$delete 这种「补丁」方法。

我在项目中就踩过这个坑:一个表格数据,后端返回了一个新字段,我用 this.data[index].newField = value 赋值,结果页面死活不更新。最后只能老老实实写 this.$set(this.data[index], 'newField', value)。你说烦不烦?

痛点四:组件体积「虚胖」

Vue2 的运行时体积大约 30KB(gzip 后),但很多功能你可能根本用不到。比如 filterinline-templateevent bus 这些,在大型项目中几乎没人用,但它们却「赖」在包里不走。

我曾经踩过的坑: 一个移动端 H5 项目,首屏加载时间超过 3 秒。分析后发现,Vue2 的完整构建包占了很大一部分。后来换成运行时构建,才勉强达标。

1.3 Vue3 的破局之道

Vue3 的诞生,说白了就是「对症下药」。尤雨溪团队花了两年多时间,从底层到上层全面重构。我个人觉得,最核心的改进有这几点:

破局一:Composition API —— 逻辑复用的「终极方案」

Composition API 的出现,彻底解决了 mixin 的痛点。你可以把相关的逻辑抽到一个函数里,想用的时候直接调用。数据来源清晰,没有命名冲突,而且天然支持 TypeScript。

// 以前用 mixin 的写法
const myMixin = {
  data() {
    return { count: 0 }
  },
  methods: {
    increment() { this.count++ }
  }
}

// 现在用 Composition API
function useCounter() {
  const count = ref(0)
  const increment = () => count.value++
  return { count, increment }
}

你看,是不是清爽多了?我在新项目中全面拥抱 Composition API,代码的可维护性提升了不止一个档次。

破局二:基于 Proxy 的响应式系统

Vue3 用 Proxy 替代了 Object.defineProperty,这意味着:

  • 数组下标变化也能监听到
  • 对象新增/删除属性也能监听到
  • 性能更好(Proxy 是懒代理,按需触发)

说白了,你再也不用写 $set$delete 了。直接赋值,页面自动更新。这个体验,谁用谁知道。

破局三:Tree-shaking 友好

Vue3 的源码采用了 ES Module 的写法,配合打包工具的 Tree-shaking,没用到的功能会被自动「摇掉」。最终打包体积可以控制在 10KB 左右(gzip 后),比 Vue2 小了将近 2/3。

我的建议: 如果你在做移动端项目,Vue3 的体积优势非常明显。首屏加载时间能减少 1-2 秒,用户体验提升巨大。

破局四:TypeScript 原生支持

Vue3 的源码本身就是用 TypeScript 写的,所以对 TS 的支持是「原生」的。你不需要任何额外的装饰器或插件,直接写 <script setup lang="ts"> 就能获得完整的类型推导。

<script setup lang="ts">
interface Props {
  title: string
  count?: number
}

const props = defineProps<Props>()
// 这里 props.title 和 props.count 都有完整的类型提示
</script>

1.4 迁移还是不迁移?

这个问题我经常被问到。我的建议是:

项目类型 建议 理由
新项目 直接上 Vue3 没有历史包袱,享受最新特性
中小型 Vue2 项目 按需迁移 核心模块用 Composition API 重写,其他保持原样
大型 Vue2 项目 谨慎评估 建议先升级到 Vue2.7,再逐步迁移到 Vue3

嗯,这里要注意一点:Vue3 不是 Vue2 的「升级版」,而是一次「重写」。所以迁移时不要想着「平滑过渡」,而是要做好「重构」的心理准备。

1.5 小结

Vue3 的出现,不是 Vue2 不够好,而是前端开发的需求变了。TypeScript 的普及、组件库的复杂化、性能要求的提升,都倒逼着框架进化。

我个人觉得,Vue3 最大的贡献不是那些新 API,而是它重新定义了「如何组织前端代码」。Composition API 让逻辑复用变得优雅,Proxy 让响应式系统变得可靠,Tree-shaking 让打包体积变得可控。

说白了,Vue3 就是 Vue2 的「完全体」—— 解决了痛点,保留了优点,还带来了新的可能性。接下来的章节,我会带你深入理解每一个新特性,并给出实际的迁移方案。准备好了吗?我们开始吧。