溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

vue3響應(yīng)式原理和api編寫的方法是什么

發(fā)布時間:2021-12-10 15:03:40 來源:億速云 閱讀:148 作者:iii 欄目:編程語言

這篇文章主要講解了“vue3響應(yīng)式原理和api編寫的方法是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“vue3響應(yīng)式原理和api編寫的方法是什么”吧!

前言

vue3響應(yīng)式原理加api編寫,快速明白vue3響應(yīng)式原理


vue3響應(yīng)式原理實(shí)現(xiàn)

先寫一段代碼看下

實(shí)現(xiàn)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歲

看看有什么可以優(yōu)化的點(diǎn)呢?

首先:多個函數(shù),在age發(fā)生變化后需要手動再次調(diào)用多個函數(shù)才可以獲取最新信息

期望可以修改信息以后自動調(diào)用多個函數(shù)

如何實(shí)現(xiàn)呢

可以想到將多個函數(shù)存放到一起存放到gather函數(shù),并且讓age發(fā)生變化時可以將多個函數(shù)調(diào)用trigger調(diào)用

實(shí)現(xiàn)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歲

再繼續(xù)看下還是有什么可以優(yōu)化的點(diǎn)

如果變量是一個對象或多個對象的話該怎么處理呢

  • 變量為原始類型時Set存儲

  • 變量為對象時可以用map存儲

  • 多個對象時用weakMap存儲

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歲

在繼續(xù)看看有哪些可以優(yōu)化的點(diǎn)

上邊依賴的收集gather以及函數(shù)的更新通知trigger每次都是手動收集手動觸發(fā)更新,那有什么方法可以自動收集及觸發(fā)嗎

Proxy

實(shí)現(xiàn)reactive

先寫一個reactive函數(shù)

function reactive(target) {
  const handle = {
    set(target, key, value, receiver) {
      Reflect.set(target, key, value, receiver);
      trigger(receiver,key) // 設(shè)置值時觸發(fā)自動更新
    },
    get(target, key, receiver) {
      gather(receiver, key); // 訪問時收集依賴
      return Reflect.get(target, key, receiver);
    },
  };
  return new Proxy(target, handle);
}

然后將reactive函數(shù)應(yīng)用到之前代碼

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函數(shù)中有寫死dep添加函數(shù)

如何解決呢 重寫effect函數(shù)

let activeEffect = null
function effect(fn) {
  activeEffect = fn;
  activeEffect();
  activeEffect = null; // 執(zhí)行后立馬變成null
}
var depsMap = new WeakMap();
function gather(target, key) {
  // 避免例如console.log(obj1.name)而觸發(fā)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) //將函數(shù)添加到依賴
}
effect(effect1);
effect(effect2);

reactive也已經(jīng)實(shí)現(xiàn)了,那么還有ref也實(shí)現(xiàn)下

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)而觸發(fā)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); // 設(shè)置值時觸發(fā)自動更新
    },
    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
        }
    )
}

感謝各位的閱讀,以上就是“vue3響應(yīng)式原理和api編寫的方法是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對vue3響應(yīng)式原理和api編寫的方法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI