先使用Vue3的reactivity的包测试下响应式的效果:

    1. const { reactive, effect } = require("@vue/reactivity");
    2. let a = reactive({ value: 10 });
    3. let b;
    4. effect(() => {
    5. b = a.value + 10;
    6. console.log(b);
    7. });
    8. a.value = 20;
    9. // 20 会先执行一次
    10. // 30 发生变化之后,执行一次

    通过依赖收集进行响应触发,在get的时候进行effect函数的收集,在set的时候进行effect函数的触发。

    1. /*
    2. * @Description:
    3. * @Author: zhaodacheng5
    4. * @Date: 2021-05-26 12:26:11
    5. * @LastEditors: zhaodacheng5
    6. * @LastEditTime: 2021-05-26 14:43:36
    7. */
    8. class Dep {
    9. constructor(val) {
    10. this.effects = new Set();
    11. this._val = val;
    12. }
    13. get value() {
    14. return this._val;
    15. this.depend();
    16. }
    17. set value(val) {
    18. this._val = val;
    19. this.notice();
    20. }
    21. // 收集依赖
    22. depend() {
    23. if (curEffect) this.effects.add(curEffect);
    24. }
    25. //触发依赖
    26. notice() {
    27. this.effects.forEach((effect) => {
    28. effect();
    29. });
    30. }
    31. }
    32. let curEffect; // 当前作用函数
    33. function effectWatch(effect) {
    34. //收集依赖
    35. curEffect = effect;
    36. effect();
    37. curEffect = null;
    38. }
    39. //test 值报错在dep对象里
    40. const dep = new Dep(10);
    41. let b;
    42. effectWatch(() => {
    43. b = dep.value + 10;
    44. console.log("change:"+b);
    45. });
    46. dep.value = 20;

    把数据进行分离,使用proxy代理,对象的get和set方法:

    1. /*
    2. * @Description:
    3. * @Author: zhaodacheng5
    4. * @Date: 2021-05-26 12:26:11
    5. * @LastEditors: zhaodacheng5
    6. * @LastEditTime: 2021-05-26 13:54:26
    7. */
    8. class Dep {
    9. constructor() {
    10. this.effects = new Set();
    11. }
    12. // 收集依赖
    13. depend() {
    14. if (curEffect) this.effects.add(curEffect);
    15. }
    16. //触发依赖
    17. notice() {
    18. this.effects.forEach((effect) => {
    19. effect();
    20. });
    21. }
    22. }
    23. let curEffect; // 当前副作用函数
    24. function effectWatch(effect) {
    25. //收集依赖
    26. curEffect = effect;
    27. effect();
    28. curEffect = null;
    29. }
    30. const targetMap = new Map();
    31. // target - depsMap
    32. // key - dep 一个对象有多个key
    33. function getDep(target, key) {
    34. let depsMap = targetMap.get(target);
    35. if (!depsMap) {
    36. depsMap = new Map();
    37. targetMap.set(target, depsMap);
    38. }
    39. let dep = depsMap.get(key);
    40. if (!dep) {
    41. dep = new Dep();
    42. depsMap.set(key, dep);
    43. }
    44. return dep;
    45. }
    46. function reactive(raw) {
    47. return new Proxy(raw, {
    48. get(target, key) {
    49. const dep = getDep(target, key);
    50. //依赖收集
    51. dep.depend();
    52. //返回值
    53. return Reflect.get(target, key);
    54. },
    55. set(target, key, value) {
    56. const dep = getDep(target, key);
    57. const result = Reflect.set(target, key, value);
    58. //触发
    59. dep.notice();
    60. return result;
    61. },
    62. });
    63. }
    64. //test
    65. let a = reactive({ value: 10 });
    66. let b;
    67. effectWatch(() => {
    68. b = a.value + 10;
    69. console.log(b);
    70. });
    71. 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