Vue 2 vs Vue 3

1. 响应式系统

Vue 2:Object.defineProperty

// Vue 2 响应式原理
data() {
  return {
    user: { name: 'john' }
  }
}
  • 遍历 data 对象每个属性,用 Object.defineProperty 转换为 getter/setter
  • 缺点
    • 无法监听新增/删除属性(需要 Vue.set/Vue.delete)
    • 无法监听数组下标变化(只有修改 7 个数组方法才能触发)
    • 初始化时需要递归遍历整个对象,深层嵌套很慢

Vue 3:Proxy

// Vue 3 响应式原理
const state = reactive({
  user: { name: "john" },
});
  • 用 ES6 Proxy 拦截整个对象
  • 优点
    • 能监听新增/删除属性
    • 能监听数组下标
    • 惰性代理(只有访问到的层级才代理)
  • 注意:Proxy 不能代理基本类型,需要用 ref 包装

2. API 风格

Vue 2:Options API

export default {
  data() {
    return { count: 0 };
  },
  methods: {
    increment() {
      this.count++;
    },
  },
  computed: {
    double() {
      return this.count * 2;
    },
  },
};
  • 按选项分类:data、methods、computed、watch、生命周期
  • 问题:逻辑分散,一个功能的相关代码散落在不同选项中
  • 复用:用 Mixin(容易出现命名冲突、数据来源不清晰)

Vue 3:Composition API

// setup 是入口
setup() {
  const count = ref(0)
  const double = computed(() => count.value * 2)

  function increment() {
    count.value++
  }

  // 相关逻辑放一起
  return { count, double, increment }
}
  • 按逻辑功能聚合代码
  • 复用:抽取为 Composable 函数(Hooks),更清晰
  • 新增 <script setup> 语法糖,代码更简洁

3. 性能提升

打包体积

  • Vue 2:全量打包,无法 Tree-shaking
  • Vue 3:按需引入,体积更小(Vue 3 完整版约 20KB+)

渲染性能

优化点说明
Patch Flags编译时标记动态节点,Diff 时只对比变化部分
Hoist Static静态节点提升到渲染函数外,只创建一次
Block Tree收集动态节点为扁平数组,Diff 只需遍历动态节点
缓存事件处理相同的 @click 处理函数会被缓存

内存占用

  • Vue 3 重新设计,相同功能下内存占用更少

4. 新特性

Fragment(多根节点)

<!-- Vue 2:必须用一个根元素包裹 -->
<template>
  <div>
    <header></header>
    <main></main>
  </div>
</template>

<!-- Vue 3:支持多根节点 -->
<template>
  <header></header>
  <main></main>
</template>

Teleport(传送门)

<Teleport to="body">
  <Modal />
</Teleport>

把组件渲染到 body 下,不受父级 overflow/z-index 影响。

Suspense(异步等待)

<Suspense>
  <template #default>
    <AsyncComponent />
  </template>
  <template #fallback>
    <Loading />
  </template>
</Suspense>

CSS v-bind

<template>
  <div class="box">内容</div>
</template>

<script setup>
const color = ref("red");
</script>

<style scoped>
.box {
  background: v-bind(color);
}
</style>

5. 生命周期

对比表

Vue 2Vue 3
beforeCreatesetup()
createdsetup()
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted
errorCapturedonErrorCaptured

变化

  • setup() 在 beforeCreate 之前执行
  • 新增:onRenderTracked(跟踪)、onRenderTriggered(触发)
  • 废弃:componentWillMount、componentWillReceiveProps、componentWillUpdate(UNSAFE)

6. 组件

v-model

Vue 2Vue 3
prop: valueprop: modelValue
event: inputevent: update:modelValue
多个 v-model 用 .sync多个 v-model 原生支持

插槽

Vue 2Vue 3
作用域插槽编译成函数所有插槽都是函数
父组件更新,子组件也更新父子更新隔离

defineExpose

// Vue 2:组件实例暴露一切
export default {
  methods: {
    focus() {},
  },
};

// Vue 3:默认不暴露
defineExpose({
  focus() {},
});

7. TypeScript 支持

Vue 2

  • 最初没有考虑 TS,写类型定义很痛苦
  • 需要 vue-class-component 等装饰器库
  • 推导能力弱

Vue 3

  • 完全用 TS 重写
  • 天然类型推导
  • Composition API + TypeScript 完美配合
// Vue 3 + TS = 类型推导丝滑
const count = ref<number>(0);
const doubled = computed<number>(() => count.value * 2);

8. 构建工具

Vue 2

  • Webpack
  • 启动慢,热更新慢

Vue 3

  • Vite
  • ES Module + 浏览器的原生 ESM
  • 秒级启动、热更新极快

9. 移除的特性

Filters

<!-- Vue 2 -->
{{ message | capitalize }}

<!-- Vue 3:不支持,用方法或 computed 代替 -->
{{ capitalize(message) }}

EventBus

// Vue 2
this.$on("event", fn);
this.$emit("event");

// Vue 3:移除,用 mitt 库替代
import mitt from "mitt";
const emitter = mitt();
emitter.on("event", fn);
emitter.emit("event");

更改 API 风格

// Vue 2:修改 Vue 原型
Vue.prototype.$http = axios;

// Vue 3:createApp 工厂模式
const app = createApp(App);
app.config.globalProperties.$http = axios;

10. 生态环境

Vue 2Vue 3
状态管理VuexPinia(推荐)
路由vue-router 3vue-router 4
构建WebpackVite
UI 组件库Element UIElement Plus

总结

维度Vue 2Vue 3
响应式definePropertyProxy
APIOptionsComposition + script setup
性能一般提升显著
TS 支持
新特性Fragment/Teleport/Suspense
打包全量Tree-shaking
构建WebpackVite
状态管理VuexPinia
推荐场景老项目维护新项目