Vue3 对比 Vue2

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 数据结构,无需额外处理复杂类型

示例对比

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(监听登录状态)中,维护时需跨选项查找。

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

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

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

javascript 复制代码
<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,可明确导入来源。

javascript 复制代码
// 封装一个通用的"本地存储"逻辑(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 包裹。

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

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

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

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

javascript 复制代码
<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 中声明,支持类型校验,更规范。

xml 复制代码
<!-- 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,且可自定义属性名和事件名。
xml 复制代码
<!-- 父组件 -->
<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 会将静态节点提升到渲染函数外,只创建一次,复用引用。
xml 复制代码
<!-- 静态节点(无动态绑定) -->
<p>这是静态文本</p>
<!-- Vue3 编译后:静态节点只创建一次 -->
const hoisted = createVNode('p', null, '这是静态文本');
function render() {
     return [hoisted]; // 直接复用
}
  • PatchFlag 标记动态节点

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

xml 复制代码
<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 挂载在实例上,支持多应用隔离。

javascript 复制代码
// 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 中直接替代) 初始化后
beforeMount onBeforeMount 挂载前
mounted onMounted 挂载后
beforeUpdate onBeforeUpdate 更新前
updated onUpdated 更新后
beforeDestroy onBeforeUnmount 卸载前(更名为 Unmount)
destroyed onUnmounted 卸载后
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 设计天然支持类型推导,无需额外配置即可获得完整的类型提示。

ini 复制代码
// 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 的新特性。

相关推荐
clausliang3 小时前
实现一个可插入变量的文本框
前端·vue.js
yyongsheng3 小时前
SpringBoot项目集成easy-es框架
java·服务器·前端
fruge3 小时前
前端工程化流程搭建与配置优化指南
前端
Aress"3 小时前
uniapp设置vuex公共值状态管理
javascript·vue.js·uni-app
东芃93943 小时前
uniapp上传blob对象到后台
前端·javascript·uni-app
coding随想4 小时前
救命!网页还在偷偷耗电?浏览器Battery API事件教你精准控电,这5个场景用了都说香
前端
贝西奇谈4 小时前
JavaScript DOM节点操作详解
开发语言·javascript·php
IT_陈寒4 小时前
Redis性能翻倍的5个冷门优化技巧,90%的开发者都不知道第3个!
前端·人工智能·后端
华仔啊4 小时前
无需UI库!50行CSS打造丝滑弹性动效导航栏,拿来即用
前端·css