Vue3 对比 Vue2

354 阅读5分钟

Vue3 与 Vue2 的对比及升级

Vue3 作为 Vue 框架的重大升级,在响应式系统、组件逻辑组织、性能、TypeScript 支持等核心层面进行了全方位重构,解决了 Vue2 的诸多痛点(如响应式缺陷、大型组件逻辑分散、性能瓶颈等)。以下从 核心底层、开发体验、性能优化、生态工具 四大维度详细对比升级点:

一、响应式系统重构:从 Object.definePropertyProxy

Vue2 的响应式依赖 Object.defineProperty 劫持对象属性,存在天然缺陷;Vue3 改用 Proxy 代理整个对象,从底层解决了这些问题。

对比维度Vue2(Object.defineProperty)Vue3(Proxy)核心优势
监听范围只能劫持对象的 已有属性,无法监听新增 / 删除属性、数组索引 / 长度变化直接代理整个对象,可监听 新增属性、删除属性、数组索引 / 长度、Map/Set 等无需手动 this.$set 新增属性,数组 arr[0] = 1arr.length = 0 可直接响应
劫持粒度需遍历对象每个属性单独劫持(嵌套对象需递归)只代理对象本身,访问嵌套对象时才递归代理(懒劫持)初始化性能更好,尤其对大型对象(如 1000 个属性的对象,Vue3 初始化更快)
数据类型支持仅支持对象、数组,对 Map/Set 等复杂类型无响应式支持原生支持 Object/Array/Map/Set/WeakMap/WeakSet适配现代 JavaScript 数据结构,无需额外处理复杂类型

示例对比

// Vue2 中需手动 $set 新增属性

this.user.age = 20; // 无响应
this.$set(this.user, 'age', 20); // 需手动触发响应

// Vue3 中直接新增属性即可响应

this.user.age = 20; // 自动响应

// 数组操作
// Vue2 中需用变异方法(push/pop)或 \$set
this.list[0] = 1; // 无响应
this.$set(this.list, 0, 1); // 需手动触发

// Vue3 中直接修改索引即可响应
this.list[0] = 1; // 自动响应

二、组件逻辑组织:从 Options API 到 Composition API

Vue2 用 Options API(data/methods/computed 等选项)组织逻辑,大型组件会出现 “逻辑碎片化”(同一功能的代码分散在不同选项中);Vue3 推出 Composition API,按 功能逻辑 聚合代码,解决碎片化问题。

1. 核心差异:按 “功能” 而非 “选项类型” 组织代码
  • Vue2(Options API)

    同一功能的代码(如 “用户登录逻辑”)需分散在 data(定义状态)、methods(定义登录方法)、watch(监听登录状态)中,维护时需跨选项查找。

export default {
     data() {
       return { token: '', loading: false }; // 登录相关状态
     },
     methods: {
       login() { this.loading = true; /\* ... \*/ } // 登录方法
     },
     watch: {
       token(newVal) { /\* 监听登录状态 \*/ } // 登录相关监听
     }

};
  • Vue3(Composition API + <script setup>

    setup 函数(或语法糖 <script setup>)将同一功能的状态、方法、监听逻辑聚合在一起,类似 “函数式编程”,可读性和复用性大幅提升。

<script setup>
import { ref, watch } from 'vue';
// 登录功能相关逻辑聚合
const token = ref('');
const loading = ref(false);
const login = () => {
     loading.value = true;
     // ... 登录逻辑
};
watch(token, (newVal) => {
    // 监听登录状态
});
</script>
2. Composition API 的核心优势
  • 逻辑复用更灵活

    Vue2 复用逻辑依赖 mixin,但存在 “命名冲突”“来源不明确” 等问题;Vue3 用 组合函数(Composables) 复用逻辑,类似 React Hooks,可明确导入来源。

// 封装一个通用的"本地存储"逻辑(composables/useStorage.js)

import { ref, watch } from 'vue';
export const useStorage = (key, defaultValue) => {
     const value = ref(JSON.parse(localStorage.getItem(key)) || defaultValue);
     watch(value, (newVal) => {
       localStorage.setItem(key, JSON.stringify(newVal));
     });
     return { value };
};

// 在组件中复用(无冲突,来源明确)
<script setup>
    import { useStorage } from './composables/useStorage';
    const { value: token } = useStorage('token', ''); // 复用本地存储逻辑
</script>
  • TypeScript 友好

    Options API 中 this 指向模糊,TypeScript 类型推导困难;Composition API 基于函数参数和返回值,类型定义清晰,无需额外类型声明。

三、模板语法与组件能力增强

Vue3 对模板和组件功能进行了多项实用升级,解决了 Vue2 的诸多限制。

1. 模板语法增强
  • 多根节点(Fragment)

    Vue2 组件模板必须有唯一根节点(否则报错);Vue3 支持多根节点,无需用冗余 div 包裹。

<!-- Vue2(错误) -->
<template>
     <h1>标题</h1>
     <p>内容</p> <!-- 报错:模板必须有唯一根节点 -->
</template>
<!-- Vue3(正确) -->
<template>
     <h1>标题</h1>
     <p>内容</p> <!-- 支持多根节点 -->
</template>
  • Teleport(传送门)

    解决 “组件嵌套层级过深导致的样式 / 事件冒泡问题”,可将组件内容渲染到 DOM 任意位置(如 body 下),适合模态框、通知组件。

<template>
     <button @click="show = true">打开弹窗</button>
     <Teleport to="body"> <!-- 将弹窗渲染到 body 下 -->
       <div class="modal" v-if="show">
         <p>弹窗内容(不受父组件样式影响)</p>
       </div>
     </Teleport>
</template>
  • Suspense

    简化异步组件的加载状态管理,无需手动写 v-if 判断加载 / 错误状态。

<template>
     <Suspense>
       <!-- 异步组件 -->
       <template #default>
         <AsyncComponent /> <!-- 加载成功时显示 -->
       </template>
       <!-- 加载中状态 -->
       <template #fallback>
         <div>加载中...</div>
       </template>
     </Suspense>
</template>
<script setup>

// 异步导入组件
const AsyncComponent = defineAsyncComponent(() => import('./AsyncComponent.vue'));
</script>
2. 组件通信与 v-model 重构
  • 自定义事件显式声明(emits 选项)

    Vue2 中组件自定义事件通过 this.$emit 触发,无显式声明,可读性差;Vue3 需在 emits 中声明,支持类型校验,更规范。

<!-- Vue3 组件 -->
<script setup>
// 显式声明自定义事件,支持校验
const emits = defineEmits({
     // 校验事件参数
     'change': (value) => value > 0 || '值必须大于0'
});
const handleClick = () => {
     emits('change', 10); // 触发事件
};
</script>
  • v-model 灵活绑定: Vue2 中一个组件只能用 v-model 绑定一个值(默认 value 属性 + input 事件);Vue3 支持 多个 v-model,且可自定义属性名和事件名。
<!-- 父组件 -->
<ChildComponent
     v-model:name="username"
     v-model:age="userAge"
/>
<!-- 子组件 -->
<script setup>
const props = defineProps(\['name', 'age']);
const emits = defineEmits(\['update:name', 'update:age']);
// 更新 name
emits('update:name', '新名字');
// 更新 age
emits('update:age', 20);
</script>

四、性能全方位优化

Vue3 在 编译时运行时 进行了多项优化,性能比 Vue2 提升约 55%(官方基准测试数据)。

1. 编译阶段优化
  • 静态提升(Hoist Static): Vue2 每次渲染都会重新创建静态节点(如纯文本、无动态绑定的元素);Vue3 会将静态节点提升到渲染函数外,只创建一次,复用引用。
<!-- 静态节点(无动态绑定) -->
<p>这是静态文本</p>
<!-- Vue3 编译后:静态节点只创建一次 -->
const hoisted = createVNode('p', null, '这是静态文本');
function render() {
     return [hoisted]; // 直接复用
}
  • PatchFlag 标记动态节点

    Vue2 的 diff 算法会遍历所有节点对比;Vue3 在编译时给 动态节点 打上标记(如 PatchFlag: TEXT 表示只有文本变化),diff 时只对比带标记的节点,减少 90%+ 的比对开销。

<p :class="cls">Hello {{ name }}</p>
<!-- Vue3 编译后:标记动态部分 -->
createVNode('p',
     { class: cls },
     [createTextVNode(\`Hello \${name}\`, PatchFlag.TEXT)] // 仅文本动态
)
  • 事件缓存(Cache Handlers): Vue2 中 @click="handleClick" 每次渲染都会创建新的函数引用,导致组件重新渲染;Vue3 会缓存事件处理函数,避免不必要的重渲染。
2. 运行时优化
  • 更小的打包体积: Vue3 支持 Tree-Shaking(摇树优化),未使用的 API(如 v-showtransition)会被打包工具剔除,核心库体积从 Vue2 的 23KB 降至 10KB 左右(gzip 后)。

  • 虚拟 DOM 优化: Vue3 重写了虚拟 DOM 实现,减少了创建虚拟节点的开销,且对编译时已知的动态节点做了针对性优化(如静态属性直接复用)。

五、API 与生态工具升级

1. 全局 API 调整:从 “全局对象” 到 “实例化”

Vue2 的全局 API(如 Vue.componentVue.directive)直接挂载在 Vue 全局对象上,导致全局污染且难以隔离;Vue3 改用 createApp 创建应用实例,API 挂载在实例上,支持多应用隔离。

// Vue2
import Vue from 'vue';
Vue.component('MyComponent', { ... }); // 全局注册,影响所有应用
new Vue({ el: '#app' });

// Vue3
import { createApp } from 'vue';
const app = createApp(App);
app.component('MyComponent', { ... }); // 仅当前应用有效
app.mount('#app');
2. 生命周期钩子调整

Vue3 保留了大部分生命周期,但在 Composition API 中以函数形式存在(前缀 on),且新增了 onRenderTracked/onRenderTriggered 用于调试响应式。

Vue2(Options API)Vue3(Composition API)说明
beforeCreate无(setup 中直接替代)初始化前
created无(setup 中直接替代)初始化后
beforeMountonBeforeMount挂载前
mountedonMounted挂载后
beforeUpdateonBeforeUpdate更新前
updatedonUpdated更新后
beforeDestroyonBeforeUnmount卸载前(更名为 Unmount)
destroyedonUnmounted卸载后
3. 生态工具升级
  • Vue Router 4:适配 Vue3,支持 Composition API(如 useRoute/useRouter),路由配置更灵活。
  • Pinia:替代 Vuex 成为官方状态管理库,简化 API(无 mutations),天然支持 TypeScript,与 Composition API 无缝集成。
  • Vite:Vue 团队开发的构建工具,替代 Webpack 作为官方推荐,开发启动速度提升 10-100 倍,支持 Vue3 单文件组件的快速热更新。

六、TypeScript 原生支持

Vue2 用 JavaScript 编写,对 TypeScript 的支持需通过 vue-class-component 等库间接实现,类型推导困难;Vue3 完全用 TypeScript 重构,API 设计天然支持类型推导,无需额外配置即可获得完整的类型提示。

// Vue3 组件类型定义(自动推导)

<script setup lang="ts">

import { ref } from 'vue';
const count = ref(0); // count 自动推导为 Ref\<number>
count.value = '123'; // 类型错误:不能赋值字符串(TS 自动报错)
// 定义 props 类型
const props = defineProps<{
     name: string;
     age?: number; // 可选属性
}>();

</script>

总结:Vue3 升级的核心价值

Vue3 从底层解决了 Vue2 的响应式缺陷,通过 Composition API 解决了大型组件的逻辑组织问题,结合编译时优化和 Tree-Shaking 大幅提升性能,同时原生支持 TypeScript 和现代前端工具链(Vite)。这些升级让 Vue 更适合开发 大型复杂应用,同时保持了对新手友好的特点。

对于现有 Vue2 项目,可通过 @vue/compat 兼容层平滑迁移,逐步享受 Vue3 的新特性。