基于Vue3从0到1实现 mini-vue【computed】
✨代码已上传至CSDN文库,如需要请点击下载min-vue,私信也可免费提供代码。
✨运行顺序 npm install ==>npm run build ==>npm run dev
✨Github mini-vue
conputed 只有在相关响应式依赖的值发生改变时才会重新计算,并具有缓存属性。
添加src/untils/index.js方法
export function isFunction(target){
return typeof target === 'function'
}
新建src/reactive/computed.js
import { isFunction } from '../untils';
import { effect, track, trigger } from './effect';
//参数getterOrOption getter或者get&set对象
export function computed(getterOrOption) {
let getter, setter;
if (isFunction(getterOrOption)) {
getter = getterOrOption;
setter = () => {
console.error('computed is readonly');
};
} else {
getter = getterOrOption.get;
setter = getterOrOption.set;
}
return new ComputedImpl(getter, setter);
}
class ComputedImpl {
constructor(getter, setter) {
this._setter = setter;
//value缓存值
this._value = undefined;
//依赖更新变为true
this._dirty = true;
//默认不立即执行,直接执行scheduler
this.effect = effect(getter, {
lazy: true,
scheduler: () => {
//调度程序
if (!this._dirty) {
this._dirty = true;
trigger(this, 'value');
}
},
});
}
get value() {
if (this._dirty) {
this._value = this.effect(); //最新值
//依赖发生改变
this._dirty = false;
track(this, 'value');
}
return this._value;
}
set value(newValue) {
this._setter(newValue);
}
}
更新src/reactive/effect.js
新增 effect 函数入参 options 如果 lazy 为 true 初始化时不立即执行,去执行调度函数 scheduler ,触发 trigger 返回当前值。当依赖的响应式数据变化时执行。
const effectStack = []; //处理effect嵌套effect
let activeEffect; //记录当前正在执行的副作用函数
export function effect(fn, options = {}) {
const effectFn = () => {
try {
activeEffect = effectFn;
effectStack.push(activeEffect);
return fn();
} finally {
//执行完成后还原
effectStack.pop();
//activeEffect = undefined;
activeEffect = effectStack[effectStack.length - 1];
}
};
if (!options.lazy) {
effectFn();
}
effectFn.scheduler = options.scheduler;
return effectFn;
}
const targetMap = new WeakMap(); //模块类全局变量
export function track(target, key) {
if (!activeEffect) {
return;
}
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let deps = depsMap.get(key);
if (!deps) {
depsMap.set(key, (deps = new Set()));
}
deps.add(activeEffect);
}
//trck的逆运算
export function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) {
return;
}
const deps = depsMap.get(key);
if (!deps) {
return;
}
deps.forEach((effectFn) => {
if (effectFn.scheduler) {
//有调度程序优先执行scheduler
effectFn.scheduler(effectFn);
} else {
//否则执行副作用函数
effectFn();
}
});
}