Vue 2 的响应式 API 和 Vue 3 的组合式 API 的详细对比,从核心机制、使用方式、代码示例及优缺点展开
以下是 Vue 2 的响应式 API 和 Vue 3 的组合式 API 的详细对比,从核心机制、使用方式、代码示例及优缺点展开:
1. Vue 2 的响应式 API
核心机制
- 基于
Object.defineProperty
:- 通过劫持对象的
getter
和setter
实现数据变化追踪。 - 限制:无法检测属性的添加/删除,且不支持数组的某些变异操作(如直接修改索引
arr[0] = ...
)。
- 通过劫持对象的
主要 API
功能 | 实现方式 | 示例 |
---|---|---|
声明响应式数据 | data 对象或 Vue.set /this.$set 添加属性 | ```javascript |
data() { return { count: 0 }; } ``` |
|
| 计算属性 | computed
对象 | javascript <br>computed: { fullName() { return this.firstName + this.lastName; } }<br>
|
| 侦听器 | watch
对象或 this.$watch
方法 | javascript <br>watch: {<br> count: (newVal) => console.log(newVal)<br>}<br>
|
| 方法 | methods
对象 | javascript <br>methods: { increment() { this.count++; } }<br>
|
生命周期钩子
- 分散在 Options 中:如
created
,mounted
,beforeDestroy
等。
2. Vue 3 的组合式 API
核心机制
- 基于
Proxy
:- 全局响应式追踪,支持检测属性的增删改,且无需
Vue.set
。 - 优势:更高效、更灵活,支持
for...in
遍历和数组变异操作。
- 全局响应式追踪,支持检测属性的增删改,且无需
核心函数
函数 | 用途 | 示例 |
---|---|---|
reactive | 将对象转为响应式(返回 Proxy) | ```javascript |
const state = reactive({ count: 0 }); ``` |
|
| ref
| 将基本类型转为响应式(返回一个 .value
对象) | javascript <br>const count = ref(0);<br>
|
| computed
| 声明计算属性(返回响应式引用) | javascript <br>const fullName = computed(() => state.firstName + state.lastName);<br>
|
| watch
| 监听数据变化(支持更灵活的选项) | javascript <br>watch(count, (newVal) => console.log(newVal));<br>
|
| onMounted
| 生命周期钩子(组合式 API 形式) | javascript <br>onMounted(() => console.log('Mounted'));<br>
|
核心函数对比
功能 | Vue 2 | Vue 3 | 说明 |
---|---|---|---|
响应式数据 | data 对象 | reactive /ref | Vue 3 需显式声明响应式,支持更灵活的类型(对象/基本类型)。 |
计算属性 | computed 对象 | computed() 函数 | Vue 3 需通过函数声明,返回值需手动返回到模板。 |
侦听器 | watch 对象 | watch() 函数 | Vue 3 支持更灵活的选项(如 deep , immediate )。 |
方法 | methods 对象 | setup() 返回函数 | Vue 3 在 setup() 中定义方法并返回,无需 this 。 |
3. 组合式 API 核心特性
(1) setup()
函数
- 入口点:所有逻辑集中在此函数中,替代 Options API 的分散选项。
- 执行时机:在
beforeCreate
和created
之前执行。 - 返回值:需返回一个对象,暴露给模板或子组件。
(2) ref
vs reactive
函数 | 适用场景 | 示例 |
---|---|---|
ref | 基本类型(如数字、字符串)或需要直接访问值的场景 | ```javascript |
const count = ref(0); console.log(count.value); ``` | ||
reactive | 复杂对象(如对象、数组)或需要直接操作属性的场景 | ```javascript |
const state = reactive({ count: 0 }); console.log(state.count); ``` | ||
(3) 生命周期钩子
- 组合式形式:通过
onXXX
前缀的函数声明(如onMounted
,onBeforeUnmount
)。 - 无需
this
:直接在setup()
中调用,无需通过this
访问。
4. 代码示例对比
(1) 声明响应式数据
// Vue 2(Options API)
export default {data() {return { count: 0 };}
};// Vue 3(组合式 API)
import { ref } from 'vue';export default {setup() {const count = ref(0);return { count };}
};
(2) 计算属性
// Vue 2
export default {computed: {fullName() {return this.firstName + ' ' + this.lastName;}}
};// Vue 3
import { computed } from 'vue';export default {setup() {const state = reactive({firstName: 'John',lastName: 'Doe'});const fullName = computed(() => state.firstName + ' ' + state.lastName);return { fullName };}
};
(3) 生命周期
// Vue 2
export default {mounted() {console.log('Mounted');}
};// Vue 3
import { onMounted } from 'vue';export default {setup() {onMounted(() => console.log('Mounted'));return {};}
};
5. 对比总结表格
特性 | Vue 2 | Vue 3(组合式 API) | 优势/差异 |
---|---|---|---|
响应式核心 | Object.defineProperty | Proxy | Vue 3 支持属性增删和更灵活的数组操作。 |
数据声明 | data 对象 | reactive /ref 显式声明 | Vue 3 需显式声明响应式,避免隐式问题。 |
计算属性 | computed 对象 | computed() 函数 | Vue 3 更灵活,支持返回函数或对象。 |
侦听器 | watch 对象 | watch() 函数 | Vue 3 支持更细粒度的选项(如 deep , flush )。 |
方法 | methods 对象 | setup() 返回函数 | Vue 3 逻辑集中,减少 Options 耦合。 |
生命周期钩子 | 分散在 Options 中 | onXXX 函数集中声明 | Vue 3 钩子名更规范(如 onMounted ),无需 this 。 |
代码复用 | Mixins(易冲突) | 自定义组合函数(无污染) | 组合式 API 更易复用且避免命名冲突。 |
模板绑定 | this.count | count (通过 ref )或 state.count (通过 reactive ) | Vue 3 需通过 ref.value 或 reactive 对象访问值。 |
6. 迁移建议
- 逐步迁移:在 Vue 2 项目中可通过
@vue/composition-api
渐进式引入组合式 API。 - 优先使用组合式 API:在新项目中推荐使用组合式 API,因其更灵活、可维护。
- 注意
ref
和reactive
的区别:根据数据类型选择合适的方式声明响应式。 - 生命周期钩子替换:Vue 3 的
setup()
会提前执行,需调整初始化逻辑顺序。
如需更详细示例,可参考 Vue 3 官方文档。