先使用Vue3的reactivity的包测试下响应式的效果:
const { reactive, effect } = require("@vue/reactivity");let a = reactive({ value: 10 });let b;effect(() => {b = a.value + 10;console.log(b);});a.value = 20;// 20 会先执行一次// 30 发生变化之后,执行一次
通过依赖收集进行响应触发,在get的时候进行effect函数的收集,在set的时候进行effect函数的触发。
/** @Description:* @Author: zhaodacheng5* @Date: 2021-05-26 12:26:11* @LastEditors: zhaodacheng5* @LastEditTime: 2021-05-26 14:43:36*/class Dep {constructor(val) {this.effects = new Set();this._val = val;}get value() {return this._val;this.depend();}set value(val) {this._val = val;this.notice();}// 收集依赖depend() {if (curEffect) this.effects.add(curEffect);}//触发依赖notice() {this.effects.forEach((effect) => {effect();});}}let curEffect; // 当前作用函数function effectWatch(effect) {//收集依赖curEffect = effect;effect();curEffect = null;}//test 值报错在dep对象里const dep = new Dep(10);let b;effectWatch(() => {b = dep.value + 10;console.log("change:"+b);});dep.value = 20;
把数据进行分离,使用proxy代理,对象的get和set方法:
/** @Description:* @Author: zhaodacheng5* @Date: 2021-05-26 12:26:11* @LastEditors: zhaodacheng5* @LastEditTime: 2021-05-26 13:54:26*/class Dep {constructor() {this.effects = new Set();}// 收集依赖depend() {if (curEffect) this.effects.add(curEffect);}//触发依赖notice() {this.effects.forEach((effect) => {effect();});}}let curEffect; // 当前副作用函数function effectWatch(effect) {//收集依赖curEffect = effect;effect();curEffect = null;}const targetMap = new Map();// target - depsMap// key - dep 一个对象有多个keyfunction getDep(target, key) {let depsMap = targetMap.get(target);if (!depsMap) {depsMap = new Map();targetMap.set(target, depsMap);}let dep = depsMap.get(key);if (!dep) {dep = new Dep();depsMap.set(key, dep);}return dep;}function reactive(raw) {return new Proxy(raw, {get(target, key) {const dep = getDep(target, key);//依赖收集dep.depend();//返回值return Reflect.get(target, key);},set(target, key, value) {const dep = getDep(target, key);const result = Reflect.set(target, key, value);//触发dep.notice();return result;},});}//testlet a = reactive({ value: 10 });let b;effectWatch(() => {b = a.value + 10;console.log(b);});a.value = 20;
参考:
https://dafunk.gitee.io/views/vue/mini-vue-reactive.html https://github.com/mewcoder/codebase/tree/main/mini-vue3 https://github.com/ReySun/vue3-deep-dive-width-evan-you
