Vue 2 vs Vue 3:全面对比指南

4 阅读6分钟

Vue 2 vs Vue 3:全面对比指南

前言:Vue 3 已经发布一段时间了,很多开发者在考虑是否要升级。本文将从多个维度详细对比 Vue 2 和 Vue 3,帮助你做出最佳选择。


📌 目录

  1. 核心概念差异
  2. 响应式系统革新
  3. 组件系统升级
  4. 生命周期钩子变化
  5. Composition API vs Options API
  6. 性能提升对比
  7. TypeScript 支持
  8. 全局 API 变更
  9. 迁移策略建议
  10. 生态系统对比

1. 核心概念差异

1.1 创建 Vue 实例的方式

Vue 2 写法:

const app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
});

Vue 3 写法:

import { createApp } from 'vue';

const app = createApp({
  data() {
    return {
      message: 'Hello Vue 3!'
    }
  }
});

app.mount('#app');

关键变化:

  • new Vue() → ✅ createApp()
  • el 选项 → ✅ mount() 方法
  • 支持多个应用实例(微前端友好)

1.2 两种 API 风格

Vue 3 保留了 Options API(兼容 Vue 2),同时引入了强大的 Composition API

// Composition API 示例
import { ref, reactive, computed } from 'vue';

setup() {
  const message = ref('Hello');
  const state = reactive({ count: 0 });
  const doubled = computed(() => state.count * 2);
  
  return { message, state, doubled };
}

2. 响应式系统革新

2.1 实现原理对比

Vue 2:Object.defineProperty(2015 年的技术)

// 存在的问题
const obj = { a: 1 };
obj.b = 2;  // ❌ 不会触发视图更新
delete obj.a;  // ❌ 不会触发视图更新

// 需要使用特殊 API
Vue.set(obj, 'b', 2);  // ✅
Vue.delete(obj, 'a');  // ✅

Vue 3:Proxy(ES6 新特性)

import { reactive } from 'vue';

const obj = reactive({ a: 1 });
obj.b = 2;   // ✅ 自动追踪
delete obj.a;  // ✅ 自动追踪

2.2 响应式 API

// ref - 用于基本类型
const count = ref(0);
count.value++;  // 需要 .value 访问

// reactive - 用于对象/数组
const state = reactive({ count: 0, list: [] });
state.count++;  // 直接访问

💡 个人建议: 优先使用 ref,统一使用 .value 访问,代码更一致。


3. 组件系统升级

3.1 组件定义方式

Vue 2:

Vue.component('todo-item', {
  props: ['title'],
  template: '<div>{{ title }}</div>'
});

Vue 3:

import { defineComponent } from 'vue';

export default defineComponent({
  props: {
    title: {
      type: String,
      required: true
    }
  },
  emits: ['update'],  // 新增 emits 声明
  setup(props, { emit }) {
    return {};
  }
});

3.2 重大改进

多根节点支持(Fragments)

<!-- Vue 3 支持 -->
<template>
  <header>...</header>
  <main>...</main>
  <footer>...</footer>
</template>

Teleport(传送门)

<teleport to="#modal">
  <div class="modal">内容</div>
</teleport>

Suspense(异步组件加载)

<suspense>
  <template #default>
    <async-component />
  </template>
  <template #fallback>
    <div>加载中...</div>
  </template>
</suspense>

4. 生命周期钩子变化

4.1 钩子函数对照表

Vue 2Vue 3 (Options)Vue 3 (Composition)说明
beforeCreatebeforeCreatesetup()初始化
createdcreatedsetup()创建完成
beforeMountbeforeMountonBeforeMount挂载前
mountedmountedonMounted挂载完成
beforeUpdatebeforeUpdateonBeforeUpdate更新前
updatedupdatedonUpdated更新后
beforeDestroybeforeUnmountonBeforeUnmount⚠️ 改名
destroyedunmountedonUnmounted⚠️ 改名

4.2 Composition API 生命周期示例

import { 
  onMounted, 
  onUpdated, 
  onBeforeUnmount 
} from 'vue';

export default {
  setup() {
    onMounted(() => {
      console.log('组件已挂载');
    });
    
    onUpdated(() => {
      console.log('组件已更新');
    });
    
    onBeforeUnmount(() => {
      console.log('组件即将卸载');
    });
  }
};

5. Composition API vs Options API

这是 Vue 3 最大的亮点!让我们看看实际对比:

5.1 Options API 的问题

// ❌ 相同功能的代码分散在不同选项中
export default {
  data() {
    return {
      searchQuery: '',
      results: [],
      loading: false,
      page: 1
    };
  },
  methods: {
    fetchResults() { /* ... */ },
    nextPage() { /* ... */ }
  },
  computed: {
    totalPages() { /* ... */ }
  },
  watch: {
    searchQuery() { /* ... */ }
  }
};

问题: 要在文件中反复横跳,维护困难!

5.2 Composition API 的解决方案

// ✅ 相关逻辑组织在一起(类似 React Hooks)
import { useSearch } from './composables/useSearch';
import { usePagination } from './composables/usePagination';

setup() {
  const { searchQuery, results, loading } = useSearch();
  const { page, totalPages, nextPage, prevPage } = usePagination();
  
  return {
    searchQuery, results, loading,
    page, totalPages, nextPage, prevPage
  };
}

5.3 自定义 Composable 示例

// composables/useSearch.js
import { ref, watch } from 'vue';

export function useSearch(apiEndpoint) {
  const searchQuery = ref('');
  const results = ref([]);
  const loading = ref(false);
  
  async function fetchResults() {
    loading.value = true;
    try {
      const res = await fetch(`${apiEndpoint}?q=${searchQuery.value}`);
      results.value = await res.json();
    } finally {
      loading.value = false;
    }
  }
  
  watch(searchQuery, fetchResults);
  
  return { searchQuery, results, loading, fetchResults };
}

// 使用
const { searchQuery, results, loading } = useSearch('/api/search');

✨ 优势:

  • 逻辑复用更简单
  • TypeScript 推断更友好
  • 代码组织更清晰
  • 测试更容易

6. 性能提升对比

先说结论:Vue 3 真香!

指标Vue 2Vue 3提升幅度
包体积~30KB~10KB3 倍减小 📦
初始渲染基准快 40%⚡️
内存占用基准减少 50%📉
更新性能基准快 1.3-2 倍⚡️
Tree-shaking🎯

Tree-shaking 示例

// Vue 3 - 只导入需要的
import { ref, computed } from 'vue';
// 未使用的功能会被打包工具移除

// Vue 2 - 导入整个 Vue
import Vue from 'vue';
// 即使用不到,也会全部打包

7. TypeScript 支持

Vue 2 + TypeScript

import Vue from 'vue';
import Component from 'vue-class-component';

@Component({
  props: { msg: String }
})
export default class MyComp extends Vue {
  count: number = 0;  // 需要装饰器
  
  increment() {
    this.count++;
  }
}

痛点: 配置复杂,类型推断有限

Vue 3 + TypeScript

import { defineComponent, ref } from 'vue';

export default defineComponent({
  props: {
    msg: {
      type: String as PropType<string>,
      required: true
    }
  },
  setup(props) {
    const count = ref<number>(0);  // 完整的类型推断
    
    return { count };
  }
});

优势: 原生 TypeScript 支持,类型推断完美!


8. 全局 API 变更

Vue 2 全局 API

import Vue from 'vue';

Vue.config.productionTip = false;
Vue.use(SomePlugin);
Vue.component('my-comp', MyComp);
Vue.directive('my-dir', MyDir);
Vue.filter('capitalize', fn);  // ❌ 已移除

new Vue({ /* options */ });

Vue 3 应用实例 API

import { createApp } from 'vue';

const app = createApp({ /* options */ });

app.config.productionTip = false;
app.use(SomePlugin);
app.component('my-comp', MyComp);
app.directive('my-dir', MyDir);
// ❌ filters 已移除

app.mount('#app');

⚠️ 破坏性变更:

  • 全局 API 移至应用实例
  • 移除过滤器 (filters)
  • 移除 $on/$off/$once
  • 移除 keyCode 修饰符

9. 迁移策略建议

渐进式迁移路线

Vue 2.x → Vue 2.7 → Vue 3 (Migration Build) → Vue 3 (Composition API)

Step 1: 升级到 Vue 2.7(包含部分 Vue 3 特性)

Step 2: 使用迁移构建版本测试

Step 3: 逐步迁移组件到 Options API

Step 4: 按需使用 Composition API 重构

Step 5: 更新生态系统(Vuex → Pinia, Router 4)

常见迁移问题

// ❌ 已移除的 API
this.$on('event', handler);
this.$off('event', handler);

// ✅ 替代方案:mitt
import mitt from 'mitt';
const emitter = mitt();
emitter.on('event', handler);

// ❌ 过滤器
{{ message | capitalize }}

// ✅ 改为函数调用
{{ capitalize(message) }}

10. 生态系统对比

工具Vue 2Vue 3推荐度
状态管理Vuex 3/4Pinia⭐⭐⭐⭐⭐
路由Vue Router 3Vue Router 4⭐⭐⭐⭐⭐
构建工具Vue CLIVite⭐⭐⭐⭐⭐
DevToolsVue DevtoolsVue Devtools 6+⭐⭐⭐⭐
UI 框架Element UIElement Plus⭐⭐⭐⭐
SSRNuxt 2Nuxt 3⭐⭐⭐⭐⭐

💡 我的推荐栈:

Vue 3 + Vite + Pinia + Vue Router 4 + Element Plus

📊 总结与选型建议

Vue 2 的优势

✅ 成熟稳定,社区资源丰富
✅ 学习曲线平缓
✅ 大量现成的组件库
✅ 适合老项目维护

Vue 3 的优势

✅ 性能大幅提升(Proxy 响应式)
✅ 包体积更小(Tree-shaking)
✅ TypeScript 支持完美
✅ Composition API 代码组织更好
✅ 更好的调试体验
✅ 长期支持(LTS)

🎯 选型建议

新项目: 无脑选 Vue 3 + Vite + Pinia
老项目: 根据业务需求决定是否迁移
学习路线: 先学 Vue 3,再了解 Vue 2 差异


🤔 常见问题 FAQ

Q1: Vue 2 停止维护了吗?
A: Vue 2 已于 2023 年 12 月 31 日结束 EOS(生命终止),不再接收安全更新。

Q2: 必须迁移到 Vue 3 吗?
A: 如果项目运行稳定且无新需求,可以不迁移。但新项目强烈建议使用 Vue 3。

Q3: Composition API 会完全取代 Options API 吗?
A: 不会。两者可以共存,根据团队偏好选择。

Q4: 学习 Composition API 难度大吗?
A: 如果有 React Hooks 经验,上手很快。纯 Vue 用户需要适应一下思维方式。


📝 参考资料:


如果这篇文章对你有帮助,欢迎点赞收藏!有任何问题欢迎在评论区留言讨论~

标签: #Vue #Vue3 #前端开发 #JavaScript #Web 开发