首先我们先来了解,什么是vue
Vue 是一款渐进式 JavaScript 框架,用于构建用户界面。综合了 Angular 的模块化和 React 的虚拟 DOM 的优点。采用了 MVVM 的设计模式,实现了双向数据绑定。通过数据驱动和组件化的开发方式,使得前端开发变得更加简单、高效。
那么他有什么优点呢?
-
双向数据绑定: Vue采用MVVM模式,相比传统的MVC模式,突破了单向数据绑定的限制,实现了数据与视图的双向实时同步。
实现原理: Vue2通过Object.defineProperty进行数据劫持,结合发布-订阅模式实现双向绑定。Vue3则采用Proxy代理机制实现。(具体区别,会在下文解释)
实现了:
- 数据变更时,视图自动更新;
- 用户操作视图时,数据同步更新。
- 组件化开发:Vue 鼓励使用组件化开发,将页面拆分成多个独立的组件,每个组件负责特定的功能。组件可以复用、嵌套和组合,提高代码的可维护性和复用性。
- 虚拟 DOM:Vue 采用了虚拟 DOM 技术,通过在内存中构建虚拟 DOM,并与真实 DOM 进行比较,只更新需要更新的部分,减少真实 DOM 操作,提高了渲染性能。
- 渐进式:Vue 是一款渐进式 JavaScript 框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性,根据业务需求逐步选择需要的 vue 功能模块。
- 生态丰富:Vue 拥有一个活跃的社区,有大量的第三方插件和工具可以使用。同时,Vue 也提供了官方的路由、状态管理和构建工具等配套库,方便开发者进行项目开发。
Vue 3 是 Vue.js 框架的一次重大革新,在性能、开发体验、可维护性和扩展性上都带来了显著提升。以下是 Vue 2 与 Vue 3 的核心差异详解:
一、核心架构与响应式系统
1.响应式原理的重构 (最核心差异)
Vue 2:使用Object.defineProperty 数据劫持 结合 订阅发布模式 实现双向数据绑定
通过 Object.defineProperty 来劫持各个属性的 getter 和 setter,当数据对象的属性被读取或修改时,会触发相应的 getter 和 setter 函数。当数据发生变化时,触发 setter 函数会通知相应的 Dep 调度器,Dep 调度器通知相应的订阅者,让订阅者执行自己的 update 逻辑进行更新视图。
-
局限性:
-
无法检测属性的添加或删除:
-
Object.defineProperty 数据劫持,只能劫持对象当前已有的属性,不能监听到对象的新增或删除属性,因此为了保持对象的响应性需要使用
Vue.set/Vue.delete
或this.$set/this.$delete
。
-
数组监听不完善: 无法直接通过索引修改 (
arr[index] = newValue
) 或修改length
触发响应。需要重写数组的方法 (push
,pop
,shift
,unshift
,splice
,sort
,reverse
) 来实现响应。 -
性能开销: 初始化时需要递归遍历整个对象,如果对象层级深、属性多,性能开销较大。
Vue3 :通过 Proxy 数据代理 来实现的数据双向绑定
使用 ES6 的
Proxy
对象包裹整个data
对象。Proxy
提供了一种机制,可以拦截并定义对象的基本操作(如属性查找、赋值、枚举、函数调用等),并返回一个新对象。ES6 提供 Proxy 构造函数,用来生成 Proxy 实例,接收两个参数 target 和 handler。target 是用 Proxy 包装的被代理对象,可以是任何类型的对象,包括原生数组,函数,甚至是另外一个代理。handler 是一个对象,其声明了代理 target 的一些操作,当任何一个对象属性发生变化时,就会触发 handler 中的 set 方法,从而更新对应的DOM节点。
优点:
-
检测属性添加/删除: 天然支持,无需特殊 API。
-
完美支持数组: 直接通过索引修改或修改
length
都能触发响应。 -
支持 Map, Set, WeakMap, WeakSet: 原生支持这些集合类型。
-
性能优化: 惰性监听(访问到深层属性时才创建代理),避免初始化时的全量递归遍历,尤其对大型对象性能提升显著。
-
更强大的拦截能力:
Proxy
提供了多达 13 种拦截操作,为未来扩展提供了基础。
2.Composition API (组合式 API)
Vue 2: Options API(选项式 API)
-
通过定义一组选项对象 (
data
,methods
,computed
,watch
,props
,lifecycle hooks
等) 来组织组件逻辑。 -
优点: 结构清晰,约定俗成,对于简单组件易于理解。
-
缺点:
-
逻辑关注点分散: 一个功能相关的代码(数据、方法、计算属性、生命周期逻辑)可能被拆分到不同的选项中,使得理解和维护复杂组件的逻辑变得困难(尤其在组件变大时)。
-
逻辑复用困难: 主要通过
mixins
、高阶组件 (HOC) 或作用域插槽实现,但这些模式各有缺点:-
mixins
:命名冲突、来源不清晰、隐式依赖。 -
HOC:组件嵌套过深,props 来源不明。
-
-
Vue 3: Composition API (与 Options API 并存)
-
引入一组基于函数的 API (
ref
,reactive
,computed
,watch
,watchEffect
,onMounted
,provide/inject
,setup
等)。 -
核心是
setup()
函数:它是组件的入口点,在beforeCreate
之前执行,接收props
和context
(包含attrs
,slots
,emit
)。-
setup()
返回一个对象,该对象中暴露的属性和方法可以在模板中使用。 -
setup()
内部可以调用其他 Composition 函数。 -
可以直接使用<script setup>语法糖
-
-
优势
-
逻辑组合与复用: 可以将一个功能相关的所有逻辑(状态、计算、方法、副作用)封装在一个独立的 Composition 函数中(称为
composable
)。这个函数可以像普通函数一样在多个组件中导入和使用,实现高度可复用、低耦合的逻辑片段。 -
更好的代码组织: 开发者可以自由地按逻辑关注点(而非选项类型)组织代码。相关的代码紧密聚集在一起,大幅提升大型组件的可读性和可维护性。
-
更好的 TypeScript 集成: 函数式的 API 天生对类型推导更友好,
setup()
的输入 (props
,context
) 和输出都可以方便地进行类型标注。 -
更灵活的代码共享:
composables
比mixins
和 HOC 更灵活、更强大,避免了命名冲突和来源模糊的问题。
-
二、生命周期发生了改变
-
beforeCreate
和created
被setup()
替代(逻辑写在setup()
里)。 -
beforeMount
->onBeforeMount
-
mounted
->onMounted
-
beforeUpdate
->onBeforeUpdate
-
updated
->onUpdated
-
beforeDestroy
->onBeforeUnmount
(改名) -
destroyed
->onUnmounted
(改名) -
activated
->onActivated
-
deactivated
->onDeactivated
-
errorCaptured
->onErrorCaptured
-
vue3新增:
-
onRenderTracked
(开发调试) - 当响应式依赖被追踪时调用。 -
onRenderTriggered
(开发调试) - 当响应式依赖触发重新渲染时调用。 -
onServerPrefetch
(SSR) - 在组件实例在服务器上被渲染之前调用。
-
-
重要: Vue 3 的生命周期钩子只能在
setup()
内部或 Composition API 函数中通过import { onMounted, ... } from 'vue'
导入并使用。
三、Vue2 只支持一个根节点,Vue3 支持多个根节点。
四、编译优化 和 diff算法
Vue2 采用 双端比较算法(头尾指针对比)
缺陷:
-
全量递归比对整个虚拟 DOM 树,即使某些子树完全静态。
-
对动态绑定的细粒度更新支持不足,容易触发不必要的子组件更新。
-
列表重新排序时,DOM 移动次数可能较多
Vue3 的 Diff 优化策略
- 静态提升(Static Hoisting)
将静态节点(无动态绑定)提取到渲染函数外部,避免重复创建 VNode。
效果:减少内存占用和 Diff 时的比对次数。
- 补丁标志(Patch Flags)
在编译阶段分析模板,为动态绑定的节点添加标记(如 TEXT、CLASS、PROPS),标记其动态部分类型。
效果:Diff 时只需检查标记的动态属性,跳过静态内容。 - 区块树(BlockTree):Vue3引入了区块树概念,它可以跳过静态内容,快速定位到动态节点,减少了Diff时的比较次数。
总结
虽然存在一些破坏性变更和迁移成本,但 Vue 3 带来的长期收益(性能、可维护性、开发体验、未来潜力)使其成为构建现代 Vue 应用的必然选择。
特性 | Vue 2 | Vue 3 | 主要优势/变化 |
---|---|---|---|
响应式系统 | Object.defineProperty | Proxy | 更好的性能,支持动态增删属性/数组索引,支持 Map/Set |
API 风格 | Options API | Composition API (与 Options API 并存) | 更好的逻辑复用与组织,更强的 TS 支持 |
根节点限制 | 单根节点 | 多根节点 (Fragments) | 简化模板结构 |
跨 DOM 渲染 | 无 | <Teleport> | 解决模态框等组件定位问题 |
v-model | 单个 v-model , .sync 修饰符 | 多个 v-model , 移除 .sync | 更灵活的双向绑定 |
事件声明 | 无显式声明 | emits 选项 | 声明事件,提供验证,更好的文档化 |
生命周期 | beforeDestroy , destroyed | onBeforeUnmount , onUnmounted | 更准确的命名 |
全局 API | 挂载在 Vue 上 | ES 模块导出 (import { ... } ) | Tree-Shaking 友好,减小体积 |
指令钩子 | bind , inserted , update 等 | beforeMount , mounted , beforeUpdate | 更贴近组件生命周期,语义更清晰 |
$listeners | 存在 | 移除,合并到 $attrs | 透传更简单一致 |
$children | 存在 | 移除 | 推荐使用 ref 或 provide/inject |
插槽 ($scopedSlots ) | $scopedSlots 存在 | 移除,统一为函数形式 $slots | 语法统一,简化实现 |
TypeScript 支持 | 通过装饰器 (较好) | 原生 TS 重写,一流支持 | 类型推断更强大准确 |
构建工具 | Vue CLI (Webpack) | Vite (推荐) | 极速启动,闪电 HMR |
状态管理 | Vuex | Pinia (推荐) | 更简洁,更好的 TS 支持,取消 mutations |
key in <template v-for> | 在子元素 | 必须在 <template> 上 | - |
v-if vs v-for | v-for 优先级高 | v-if 优先级高 | 更符合直觉,避免性能浪费 (需注意变量访问) |
过滤器 (filter ) | 支持 | 移除 | 推荐使用计算属性或方法 |
事件总线 ($on/$off ) | 支持 | 移除 | 推荐使用专用库或状态管理 |
IE 11 支持 | 官方支持 | 不再支持 | 面向现代浏览器 |