“这是我参与更文挑战的第10天,活动详情查看: 更文挑战”
前文摘要
通过之前的学习,我们已经通过 Proxy + Reflect 搭建出了一个基础的响应式实现,并探索了 ref 的原理和实现。
- Vue3 响应式原理探索Part 1 - 20行代码实现响应式
- Vue3 响应式原理探索Part 2 - 多重结构的响应式
- Vue3 响应式原理探索Part 3 - Proxy + Reflect + activeEffect
- Vue3 响应式原理探索Part 4 - ref 的原理和实现
本文我们将学习 Computed Values
的实现。
computed 用法
回到之前 ref 的示例代码如下:
let param = reactive({ width: 5, height: 2 });
let size = 0;
let newWidth = ref(0);
effect(() => {
newWidth.value = param.width * 2;
});
effect(() => {
size = newWidth.value * param.height;
});
如果你已经熟悉了 Vue3 的用法,你会更习惯以下简洁的用法。
let param = reactive({ width: 5, height: 2 });
let newWidth = computed(() => {
return param.width * 2
});
let size = computed(() => {
return newWidth.value * param.height
});
它相对来说简洁优雅很多,只用 computed
包裹并赋值一次,用到的时候只要取 .value
即可。
computed 实现
function computed(getter) {
let result = ref() // 创建一个新的响应引用
effect(() => (result.value = getter())) // 在 effect 调用时, 将 getter 的返回值赋值给 result.value ,
return result // 返回引用
}
非常简洁。整体代码如下:
const targetMap = new WeakMap();
let activeEffect = null // The active effect running
function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
let dep = depsMap.get(key);
if (dep) {
dep.forEach(element => {
element();
});
}
}
function reactive(target) {
const handler = {
get(target, key, receiver) {
let result = Reflect.get(target, key, receiver);
track(target, key);
return result;
},
set(target, key, value, receiver) {
let oldValue = target[key];
let result = Reflect.set(target, key, value, receiver);
if (result && oldValue != value) {
trigger(target, key);
}
return result;
}
}
return new Proxy(target, handler);
}
function ref(raw) {
const r = {
get value() {
track(r, 'value')
return raw
},
set value(newVal) {
raw = newVal
trigger(r, 'value')
},
}
return r
}
function effect(eff) {
activeEffect = eff // Set this as the activeEffect
activeEffect() // Run it
activeEffect = null // Unset it
}
function computed(getter) {
let result = ref() // Create a new reactive reference
effect(() => (result.value = getter())) // Set this value equal to the return value of the getter
return result // return the reactive reference
}
let param = reactive({ width: 5, height: 2 });
let newWidth = computed(() => {
return param.width * 2
});
let size = computed(() => {
return newWidth.value * param.height
});
再执行如下代码,将会 console
出预期的结果。
console.log(`newWidth is ${newWidth.value}, size is ${size}`); // newWidth is 10, size is 20
param.width = 6;
console.log(`newWidth is ${newWidth.value}, size is ${size}`); // newWidth is 12, size is 24
Vue3 源码小析
我们已经建立了一个响应式的系统了(嗯,当然是非常弱鸡版本的……)。在 Vue 的真实版本中,是比这个复杂N倍的。我们可以简单列举一下Vue 源码中响应式实现相关的文件。
主要目录在 github.com/vuejs/vue-n…。
主要结构如下(截止2021年6月10日):
有兴趣的同学可以直接阅读源码。
小结
computed
用法更简洁优雅computed
的封装实现基于ref
及reactive
函数
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!