vue3 数据响应式

121 阅读1分钟

/** vue3 响应式原理;

    1. 使用proxy设置代理
    1. 使用reactive api 收集和触发依赖
    1. mount 方法中执行effect方法
    1. effect方法中执行fn,更新页面; */

/**

  • vue3 通过composition-api 的reactive api实现的响应式
  • 1.mount的时候,执行effect函数,生成activeEffect;
  • 2.执行setup函数,调用reactive api的时候,触发data对象的get方法,执行track方法收集依赖, 将activeEffect添加到targetMap【key】 = 【】 生成了响应式数据;
    1. 调用reactive api生成的数据改变的时候,触发set方法, 执行trigger方法触发依赖,将targetMap【key】中依赖遍历依次执行 reactiveEffect.run();
    1. 执行依赖 reactiveEffect.run()的时候,就是执行了effect的回调函数,去更新页面; */
let isObject = data => data && typeof data === "object";
let targetMap = new WeakMap();
let activeEffect = null;

//  发布订阅模式
// 收集依赖【依赖就是 ReactiveEffect实例 ,实例有两个属性: effect函数的参数、run函数】
function track(target,key) {
    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());
    }
    trackEffect(dep);
}
function trackEffect(dep) {
    if(!dep.has(activeEffect)){
        dep.add(activeEffect);
    }
}
function trigger(target,key) {
    let depsMap = targetMap.get(target);
    let dep = depsMap.get(key);
    (dep || []).forEach(effect => {
        effect.run();
    });
}
export function reactive(data) {
    return new Proxy(data, {
        get(target,key,receiver){
            if(!isObject(data)) return;
            let ret = Reflect.get(target,key,receiver);
            track(target,key);
            isObject(ret) ? reactive(ret) : ret;
            return ret;
        },
        set(target,key,value,receiver){
            Reflect.set(target,key,value,receiver);
            trigger(target,key);
            return true;
        },
        deleteProperty(target,key,receiver){
            let ret = Reflect.deleteProperty(target,key,receiver);
            trigger(target,key);
            return ret;
        },
        has(target,key,receiver){
            let ret = Reflect.has(target,key,receiver);
            track(target,key);
            return ret;
        },
        ownKeys(target,receiver){
            return Reflect.ownKeys(target,receiver);
        }
    })
}

function effect(fn, options = {}) {
    let __effect = new ReactiveEffect(fn);
    options.lazy || __effect.run();
    return __effect;
}
class ReactiveEffect {
    constructor(fn){
        this.fn = fn;
    }
    run(){
        activeEffect = this;
        return this.fn();
    }
}
export function mount(ins, el) {
    effect(() => {
        ins.$data && update(ins, el);
    })
    ins.$data = ins.setup();
    update(ins,el);
    function update(ins, el) {
        el.innerHTML = ins.render();
    }
}

export function ref(init){
    class RefImpl {
        constructor(init){
            this.__value = init;
        }
        get value(){
            track(this, 'value');
            return this.__value;
        }
        set value(newVal){
            this.__value = newVal;
            trigger(this, 'value');
        }
    }
    return new RefImpl(init);
}

export function computed(fn){
    let __computed;
    const e = effect(fn, {lazy: true});
    __computed = {
        get value() {
            return e.run();
        }
    }
    return __computed;
}

// diff 算法; // vue-i18n 多语言的变量的配置: 变量属性: <div :title="${$t{'confirm'}}"> 变量文本: {{ $t(${confirm})}}