• 技术文章 >web前端 >Vue.js

    解析vue3响应式原理以及api编写

    藏色散人藏色散人2021-12-10 14:57:47转载140

    前言

    vue3响应式原理加api编写,快速明白vue3响应式原理

    GitHub博客:https://github.com/jiejiangzi/blog/issues/8

    vue3响应式原理实现

    先写一段代码看下

    实现effect

    var name = 'sl', age = 22;
    effect1 = () => `我叫${name},今年${age}岁`
    effect2 = () => `我叫${name},今年${age+1}岁`
    console.log(effect1()) //我叫sl,今年22岁
    console.log(effect2()) //我叫sl,今年23岁
    age = 30;
    console.log(effect1())  //我叫sl,今年30岁
    console.log(effect2())  //我叫sl,今年31岁

    看看有什么可以优化的点呢?

    首先:多个函数,在age发生变化后需要手动再次调用多个函数才可以获取最新信息

    期望可以修改信息以后自动调用多个函数

    如何实现呢

    可以想到将多个函数存放到一起存放到gather函数,并且让age发生变化时可以将多个函数调用trigger调用

    实现gather及trigger

    var name = "sl",
      age = 22;
    var tom, joy;
    effect1 = () => (tom = `我叫${name},今年${age}岁`);
    effect2 = () => (joy = `我叫${name},今年${age + 1}岁`);
    var dep = new Set();
    function gather() {
      dep.add(effect1);
      dep.add(effect2);
    }
    function trigger() {
      dep.forEach((effect) => effect());
    }
    gather();
    effect1()
    effect2()
    console.log(tom); //我叫sl,今年22岁
    console.log(joy); //我叫sl,今年23岁
    age = 30;
    trigger()
    console.log(tom); //我叫sl,今年30岁
    console.log(joy); //我叫sl,今年31岁

    再继续看下还是有什么可以优化的点

    如果变量是一个对象或多个对象的话该怎么处理呢

    var obj1 = { name: "tom", age: 22 };
    var obj2 = { name: "joy", age: 23 };
    var tom, joy;
    effect1 = () => (tom = `我叫${obj1.name},今年${obj1.age}岁`);
    effect2 = () => (joy = `我叫${obj2.name},今年${obj2.age}岁`);
    var depsMap = new WeakMap();
    function gather(target, key) {
      let depMap = depsMap.get(target);
      if (!depMap) {
        depsMap.set(target, (depMap = new Map()));
      }
      let dep = depMap.get(key);
      if (!dep) {
        depMap.set(key, (dep = new Set()));
      }
      if (target === obj1) {
        dep.add(effect1);
      } else {
        dep.add(effect2);
      }
    }
    function trigger(target, key) {
      let depMap = depsMap.get(target);
      if (depMap) {
        const dep = depMap.get(key);
        if (dep) {
          dep.forEach((effect) => effect());
        }
      }
    }
    gather(obj1, "age");//收集依赖
    gather(obj2, "age");//收集依赖
    effect1();
    effect2();
    console.log(tom); //我叫sl,今年22岁
    console.log(joy); //我叫sl,今年23岁
    obj1.age = 30;
    obj2.age = 10;
    trigger(obj1, "age");
    trigger(obj2, "age");
    console.log(tom); //我叫sl,今年30岁
    console.log(joy); //我叫sl,今年31岁

    在继续看看有哪些可以优化的点

    上边依赖的收集gather以及函数的更新通知trigger每次都是手动收集手动触发更新,那有什么方法可以自动收集及触发吗

    Proxy

    实现reactive

    先写一个reactive函数

    function reactive(target) {
      const handle = {
        set(target, key, value, receiver) {
          Reflect.set(target, key, value, receiver);
          trigger(receiver,key) // 设置值时触发自动更新
        },
        get(target, key, receiver) {
          gather(receiver, key); // 访问时收集依赖
          return Reflect.get(target, key, receiver);
        },
      };
      return new Proxy(target, handle);
    }

    然后将reactive函数应用到之前代码

    var obj1 = reactive({ name: "tom", age: 22 });
    var obj2 = reactive({ name: "joy", age: 23 });
    var tom, joy;
    effect1 = () => (tom = `我叫${obj1.name},今年${obj1.age}岁`);
    effect2 = () => (joy = `我叫${obj2.name},今年${obj2.age}岁`);
    var depsMap = new WeakMap();
    function gather(target, key) {
      let depMap = depsMap.get(target);
      if (!depMap) {
        depsMap.set(target, (depMap = new Map()));
      }
      let dep = depMap.get(key);
      if (!dep) {
        depMap.set(key, (dep = new Set()));
      }
      if (target === obj1) {
        dep.add(effect1);
      } else {
        dep.add(effect2);
      }
    }
    function trigger(target, key) {
      let depMap = depsMap.get(target);
      if (depMap) {
        const dep = depMap.get(key);
        if (dep) {
          dep.forEach((effect) => effect());
        }
      }
    }
    effect1();
    effect2();
    console.log(tom); //我叫sl,今年22岁
    console.log(joy); //我叫sl,今年23岁
    obj1.age = 30;
    obj2.age = 10;
    console.log(tom); //我叫sl,今年30岁
    console.log(joy); //我叫sl,今年31岁

    然后还有个问题,就是gather函数中有写死dep添加函数

    如何解决呢 重写effect函数

    let activeEffect = null
    function effect(fn) {
      activeEffect = fn;
      activeEffect();
      activeEffect = null; // 执行后立马变成null
    }
    var depsMap = new WeakMap();
    function gather(target, key) {
      // 避免例如console.log(obj1.name)而触发gather
      if (!activeEffect) return;
      let depMap = depsMap.get(target);
      if (!depMap) {
        depsMap.set(target, (depMap = new Map()));
      }
      let dep = depMap.get(key);
      if (!dep) {
        depMap.set(key, (dep = new Set()));
      }
      dep.add(activeEffect) //将函数添加到依赖
    }
    effect(effect1);
    effect(effect2);

    reactive也已经实现了,那么还有ref也实现下

    ref

    在vue3中ref怎么使用呢

    var name = ref('tom')
    console.log(name.value) // tom

    需要使用.value的方式获取值

    function ref(name){
        return reactive(
            {
                value: name
            }
        )
    }
    const name = ref('tom');
    console.log(name.value) //tom

    完整代码

    var activeEffect = null;
    function effect(fn) {
      activeEffect = fn;
      activeEffect();
      activeEffect = null; 
    }
    var depsMap = new WeakMap();
    function gather(target, key) {
      // 避免例如console.log(obj1.name)而触发gather
      if (!activeEffect) return;
      let depMap = depsMap.get(target);
      if (!depMap) {
        depsMap.set(target, (depMap = new Map()));
      }
      let dep = depMap.get(key);
      if (!dep) {
        depMap.set(key, (dep = new Set()));
      }
      dep.add(activeEffect)
    }
    function trigger(target, key) {
      let depMap = depsMap.get(target);
      if (depMap) {
        const dep = depMap.get(key);
        if (dep) {
          dep.forEach((effect) => effect());
        }
      }
    }
    function reactive(target) {
      const handle = {
        set(target, key, value, receiver) {
          Reflect.set(target, key, value, receiver);
          trigger(receiver, key); // 设置值时触发自动更新
        },
        get(target, key, receiver) {
          gather(receiver, key); // 访问时收集依赖
          return Reflect.get(target, key, receiver);
        },
      };
      return new Proxy(target, handle);
    }
    function ref(name){
        return reactive(
            {
                value: name
            }
        )
    }

    推荐学习:《最新的5个vue.js视频教程精选

    以上就是解析vue3响应式原理以及api编写的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:juejin,如有侵犯,请联系admin@php.cn删除
    专题推荐:vue3 api
    上一篇:Vue动态绑定类时要怎么避免出现 空类 情况! 下一篇:介绍Vue3中Composition API及其核心用法

    相关文章推荐

    • Vue3知识地图九:Vue配套工具之Vuecli与Router• Vue3知识地图十:VueX语法• Vue3中 ref VS reactive,浅谈它们间有何区别?• 浅析怎么使用Vue3开发一个Pagination公共组件

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网