Vue 计算属性原理
前言
本文为想学习 Vue 计算属性的前端开发者准备,涵盖 computed 的工作原理及其在 Vue 3 中的实现机制。
1. 为什么学习计算属性原理
Vue的计算属性能够描述依赖响应式状态复杂逻辑,并且计算属性值会基于其响应式依赖被缓存,只有在computed属性的响应式依赖发生变化时才会重新计算。这种特性使得计算属性在性能优化和代码简洁性方面具有显著优势。
2. 计算属性的工作原理
计算属性通过 computed 函数创建,接受一个 getter 函数,并返回一个包含 .value 属性的响应式对象。其核心原理如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
function computed(getterOrOptions) {
// getter 函数
let getter;
// setter 函数
let setter;
// 标准化参数
if (isFunction(getterOrOptions)) {
// 表面传入的是 getter 函数,不能修改计算属性的值
getter = getterOrOptions;
setter =
process.env.NODE_ENV !== "production"
? () => {
console.warn("Write operation failed: computed value is readonly");
}
: NOOP;
} else {
getter = getterOrOptions.get;
setter = getterOrOptions.set;
}
// 数据是否脏的
let dirty = true;
// 计算结果
let value;
let computed;
// 创建副作用函数
const runner = effect(getter, {
// 延时执行
lazy: true,
// 标记这是一个 computed effect 用于在 trigger 阶段的优先级排序
computed: true,
// 调度执行的实现
scheduler: () => {
if (!dirty) {
dirty = true;
// 派发通知,通知运行访问该计算属性的 activeEffect
trigger(computed, "set" /* SET */, "value");
}
},
});
// 创建 computed 对象
computed = {
__v_isRef: true,
// 暴露 effect 对象以便计算属性可以停止计算
effect: runner,
get value() {
// 计算属性的 getter
if (dirty) {
// 只有数据为脏的时候才会重新计算
value = runner();
dirty = false;
}
// 依赖收集,收集运行访问该计算属性的 activeEffect
track(computed, "get" /* GET */, "value");
return value;
},
set value(newValue) {
// 计算属性的 setter
setter(newValue);
},
};
return computed;
}
|
- 脏检查:计算属性通过
dirty 标志来判断是否需要重新计算值。当依赖的响应式数据发生变化时,调度器会将 dirty 设置为 true。
- 依赖收集:当访问计算属性的
.value 时,会调用 track 函数,将当前的副作用函数与该计算属性关联起来。
- 触发更新:当计算属性的依赖发生变化时,调度器会调用
trigger 函数,通知所有依赖该计算属性的副作用函数重新执行。
- 缓存机制:计算属性只有在其依赖发生变化时才会重新计算,这通过
dirty 标志实现,从而提高性能。
3. 可写计算属性
计算属性默认是只读的,当尝试修改一个计算属性时,会在开发环境下发出警告,但在某些情况下,我们也可以同时提供getter和setter来创建可写的计算属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('Li')
const lastName = ref('Hua')
const fullName = computed({
// getter
get() {
return firstName.value + ' ' + lastName.value
},
// setter
set(newValue) {
//这里使用的是解构赋值语法
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>
|
4. 计算属性与普通方法的区别
5. 计算属性的实际应用
计算属性在实际开发中有广泛的应用场景,例如:
- 表单输入的实时验证:可以使用计算属性来根据输入的值动态计算验证结果,从而实现实时反馈。
- 复杂数据的展示:在展示复杂数据时,可以使用计算属性来处理数据的格式化和转换,简化模板逻辑。
- 依赖于多个数据源的计算:当一个值依赖于多个响应式数据时,可以使用计算属性来集中管理这些依赖关系,提高代码的可维护性。
1
2
3
|
const total = computed(() => {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0)
})
|
6. 总结
通过学习 Vue 计算属性的工作原理,开发者可以更好地理解其内部机制,从而在实际开发中更有效地利用这一特性。计算属性不仅提高了代码的简洁性和可读性,还通过缓存机制优化了性能,是 Vue 开发中不可或缺的工具。
7. 参考资料