最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue3中reactive和ref的實(shí)現(xiàn)與區(qū)別詳解

 更新時(shí)間:2023年10月23日 15:49:12   作者:BIBI居  
reactive和ref都是vue3實(shí)現(xiàn)響應(yīng)式系統(tǒng)的api,他們是如何實(shí)現(xiàn)響應(yīng)式的呢,reactive和ref又有什么區(qū)別呢,下面小編就來(lái)和大家詳細(xì)講講,希望對(duì)大家有所幫助

前言

reactive和ref都是vue3實(shí)現(xiàn)響應(yīng)式系統(tǒng)的api,他們是如何實(shí)現(xiàn)響應(yīng)式的呢?reactive和ref又有什么區(qū)別呢,看完這篇文章,相信答案就呼之欲出了。

effect

vue3中的reactive實(shí)現(xiàn)了數(shù)據(jù)的響應(yīng)式,說(shuō)到數(shù)據(jù)響應(yīng)式離不開(kāi)effect,effect是關(guān)鍵,effect()方法是暴露給創(chuàng)作者的一種方法,參數(shù)1是一個(gè)回調(diào)函數(shù),寫(xiě)在回調(diào)函數(shù)的代碼可以用來(lái)模擬setup執(zhí)行函數(shù)的響應(yīng)式數(shù)據(jù)被寫(xiě)在template模板的數(shù)據(jù),當(dāng)數(shù)據(jù)更新之后,將effect中的回調(diào)函數(shù)再次調(diào)用,達(dá)到數(shù)據(jù)更新便更新視圖的目的。也可以把effect叫做數(shù)據(jù)相關(guān)依賴,即記錄用到響應(yīng)式數(shù)據(jù)的代碼。參數(shù)二是一個(gè)對(duì)象,里面有l(wèi)azy屬性用來(lái)規(guī)定effect的回調(diào)函數(shù)第一次是否執(zhí)行。

<body>
    <div id="app">hello</div>
    <script>
        let data={
            name:'草原一匹狼'
        }
        effect(()=>{
            let app = document.getElementById('app')
            app.innerHTML=data.name
        },{lazy:true})
          setTimeout(()=>{
           data.name='切'
        },1000)
    </script>
</body>

實(shí)現(xiàn)effect方法,保存回調(diào)函數(shù)當(dāng)數(shù)據(jù)更新再次調(diào)用回調(diào)函數(shù)達(dá)到更新視圖

export function effect(fn, options: any = {}) {//更新視圖也就是吧視圖用到數(shù)據(jù)在執(zhí)行一遍
  const effect = createReactEffect(fn, options);
  if (!options.lazy) {//如果lazy:false執(zhí)行
    effect();
  }
  return effect;
}
let uid = 0;
//每次調(diào)用都會(huì)創(chuàng)建一個(gè)effect
let activeeffect;//設(shè)置當(dāng)前effect為全局變量好進(jìn)行收集 
let effectStack = [];//保存effect 因?yàn)榭赡軙?huì)有多個(gè)effect
function createReactEffect(fn, options) {
  const effect = function reactiveEffect() {
    if (!effectStack.includes(effect)) {
      try {
        effectStack.push(effect);
        activeeffect = effect;
        fn();
      } finally {
        effectStack.pop();
        activeeffect = effectStack[effectStack.length - 1];
      }
    }
  };
  effect.id = uid++; //區(qū)別effect
  effect._isEffect = true; //區(qū)別effect 是不是響應(yīng)式的effect
  effect.raw = fn; //保存回調(diào)函數(shù)到自身
  effect.options = options; //保存用戶屬性lazy

  return effect;
}

reactive

了解完effect,接下來(lái)是實(shí)現(xiàn)reactive的具體過(guò)程:

  • 響應(yīng)式數(shù)據(jù)用proxy代理時(shí)get收集依賴
  • 響應(yīng)式數(shù)據(jù)用proxy代理時(shí)set執(zhí)行依賴

1.響應(yīng)式數(shù)據(jù)用proxy代理時(shí)get收集依賴

function createGetter(isReadonly = false, shall = false) {
  return function get(target, key, receiver) {
    const res = Reflect.get(target, key, receiver); //taget[key]

    if (!isReadonly) {
      //判斷是不是只讀 收集依賴
      Track(target, TackOpType.GET, key);//Track收集依賴 一個(gè)響應(yīng)式屬性key對(duì)應(yīng)一個(gè)effect保存起來(lái)
    }

    if (shall) {
      //只代理一層
      return res;
    }
    if (isObject(res)) {
      return isReadonly ? readonly(res) : reactive(res);
    }
    return res;
  };
}
//收集effect 獲取數(shù)據(jù)觸發(fā)get 收集依賴數(shù)據(jù)變化更新視圖 key和effect11對(duì)應(yīng)
let targetMap = new WeakMap(); //棧結(jié)構(gòu)(target ,new Map(key(key effect一一對(duì)應(yīng)),new Set(activeeffect)))
export function Track(target, type, key) {
  //對(duì)應(yīng)的key
  if (activeeffect == undefined) {
    return;
  }
  let depMAp = targetMap.get(target);
  if (!depMAp) {
    targetMap.set(target, (depMAp = new Map()));
  }
  let dep = depMAp.get(key);
  if (!dep) {
    depMAp.set(key, (dep = new Set()));
  }
  if (!dep.has(activeeffect)) {
    dep.add(activeeffect);
  }
}

2.響應(yīng)式數(shù)據(jù)用proxy代理時(shí)set執(zhí)行依賴

function createSetter(shall = false) {
  return function set(target, key, value, receive) {
    const oldValue = target[key];

    let hasKey =
      Array.isArray(oldValue) && isIntegerKey(key)
        ? Number(key) < target.length
        : hasOwn(target, key);
    const result = Reflect.set(target, key, value, receive); //獲取最新的值 對(duì)象數(shù)據(jù)已經(jīng)更新
    if (!hasKey) {
      // 新增
      trigger(target, TriggerOpTypes.ADD, key, value);
    } else {
      // 修改數(shù)組
      if (hasChange(value, oldValue)) {
        trigger(target, TriggerOpTypes.SET, key, value, oldValue);
      }
    }

    return result;
  };
}
//觸發(fā)更新依賴effect
export function trigger(target, type, key?, newValue?, oldValue?) {
  const depsMap = targetMap.get(target);
  let effectSet = new Set();
  if (!depsMap) return;
  const add = (effectAdd) => {
    if (effectAdd) {
      effectAdd.forEach((effect) => effectSet.add(effect));
    }
  };
  add(depsMap.get(key)); //獲取當(dāng)前屬性的effect
  //處理數(shù)組
  if (key == "length" && Array.isArray(target)) {
    depsMap.forEach((dep, key) => {
      if (key === "length" || key >= newValue) {
        add(dep);
      }
    });
  }else{
    //處理對(duì)象
    if(key !== undefined){
      add(depsMap.get(key))
    }
    switch(type){
      case TriggerOpTypes.ADD: 
      if(Array.isArray(target)&& isIntegerKey(key)){
        add(depsMap.get('target'))
      }
    }
  }
  effectSet.forEach((effect: any) => {
    if(effect.options.sch){
      effect.options.sch(effect)
    }else{
      effect()
    }
  });
  • 被reactive包裹的數(shù)據(jù)實(shí)現(xiàn)響應(yīng)式,首先得effec保存回調(diào)函數(shù),方便數(shù)據(jù)更新再次調(diào)用來(lái)更新視圖,
  • 當(dāng)用proxy對(duì)對(duì)象代理時(shí)get方法中將視圖用到的代碼片段即相關(guān)effect與key一一對(duì)應(yīng)保存起來(lái)
  • 當(dāng)數(shù)據(jù)改變用到proxy的set方法時(shí),用key找到對(duì)應(yīng)effect執(zhí)行

ref

相信大家都知道用reactive實(shí)現(xiàn)復(fù)雜數(shù)據(jù)代理用ref實(shí)現(xiàn)簡(jiǎn)單數(shù)據(jù)的代理,因?yàn)関ue用es6的proxy代理整個(gè)對(duì)象,而ref是給簡(jiǎn)單數(shù)據(jù)用一個(gè)對(duì)象包裹起來(lái)用object.defineproperty方式代理并且用.value訪問(wèn),如果用ref對(duì)一個(gè)對(duì)象進(jìn)行響應(yīng)式處理則會(huì)調(diào)用crtoReactive方法再次對(duì).value的屬性進(jìn)行代理。 根據(jù)上面已經(jīng)實(shí)現(xiàn)的reactive api實(shí)現(xiàn)ref就簡(jiǎn)單多了。

具體步驟為:

1.如果是簡(jiǎn)單數(shù)據(jù)就用object.defineproperty代理

2.如果是復(fù)雜數(shù)據(jù)就用createReactive方法再次代理

export function ref(target){
    return creatRef(target)
}

//創(chuàng)建實(shí)例對(duì)象
class RefImpl{
    public _v_isRef=true
    public _value
    
    public _shallow
    public _rawValue
    constructor(public target,public shallow){
        this._shallow=shallow
        this._rawValue = shallow ? target : toRaw(target)
        this._value = shallow ? target : toReactive(target)
    }
    get value(){
        Track(this,TackOpType.GET,"value")
        return this.value
    }
    set value(newVAlue){
        if(newVAlue!==this._value)
         this._rawValue=newVAlue 
         this._value = isObject(newVAlue) ? newVAlue : toReactive(newVAlue)//這是ref不失去響應(yīng)式的關(guān)鍵如果新的值就重新代理
        trigger(this,TriggerOpTypes.SET,"value",newVAlue)


    }
}
function creatRef(target,shallow=false){
    //創(chuàng)建ref實(shí)例對(duì)象
    return new RefImpl(target,shallow)
}

到此這篇關(guān)于vue3中reactive和ref的實(shí)現(xiàn)與區(qū)別詳解的文章就介紹到這了,更多相關(guān) vue3 reactive ref內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue中使用gojs/jointjs的示例代碼

    vue中使用gojs/jointjs的示例代碼

    這篇文章主要介紹了vue中使用gojs/jointjs的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • Vue 前端實(shí)現(xiàn)登陸攔截及axios 攔截器的使用

    Vue 前端實(shí)現(xiàn)登陸攔截及axios 攔截器的使用

    這篇文章主要介紹了Vue 前端實(shí)現(xiàn)登陸攔截及axios 攔截器的使用,通過(guò)這個(gè)項(xiàng)目學(xué)習(xí)如何實(shí)現(xiàn)一個(gè)前端項(xiàng)目中所需要的 登錄及攔截、登出、token失效的攔截及對(duì)應(yīng) axios 攔截器的使用。需要的朋友可以參考下
    2019-07-07
  • 深入理解Vue.js3中Reactive的實(shí)現(xiàn)

    深入理解Vue.js3中Reactive的實(shí)現(xiàn)

    reactive是Vue 3的Composition API中的一個(gè)函數(shù),它允許你創(chuàng)建一個(gè)響應(yīng)式的數(shù)據(jù)對(duì)象,本文主要介紹了深入理解Vue.js3中Reactive的實(shí)現(xiàn),感興趣的可以了解一下
    2024-01-01
  • vue中自定義組件雙向綁定的三種方法總結(jié)

    vue中自定義組件雙向綁定的三種方法總結(jié)

    這篇文章主要介紹了vue中自定義組件雙向綁定的三種方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • vue+springboot實(shí)現(xiàn)登錄功能

    vue+springboot實(shí)現(xiàn)登錄功能

    這篇文章主要為大家詳細(xì)介紹了vue+springboot實(shí)現(xiàn)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • VUE微信H5生成二維碼海報(bào)保存在本地相冊(cè)的實(shí)現(xiàn)

    VUE微信H5生成二維碼海報(bào)保存在本地相冊(cè)的實(shí)現(xiàn)

    本文主要介紹了VUE微信H5生成二維碼海報(bào)保存在本地相冊(cè)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Vue + Element UI圖片上傳控件使用詳解

    Vue + Element UI圖片上傳控件使用詳解

    這篇文章主要為大家詳細(xì)介紹了Vue + Element UI圖片上傳控件的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Vue中的計(jì)算屬性和axios基本使用回顧

    Vue中的計(jì)算屬性和axios基本使用回顧

    這篇文章主要介紹了Vue中的計(jì)算屬性和axios基本使用回顧,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • axios請(qǐng)求頭設(shè)置常見(jiàn)Content-Type和對(duì)應(yīng)參數(shù)的處理方式

    axios請(qǐng)求頭設(shè)置常見(jiàn)Content-Type和對(duì)應(yīng)參數(shù)的處理方式

    這篇文章主要介紹了axios請(qǐng)求頭設(shè)置常見(jiàn)Content-Type和對(duì)應(yīng)參數(shù)的處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • vue如何解決this.refs拿取v-for下元素undefine問(wèn)題

    vue如何解決this.refs拿取v-for下元素undefine問(wèn)題

    這篇文章主要介紹了vue如何解決this.refs拿取v-for下元素undefine問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05

最新評(píng)論

泸定县| 乐都县| 边坝县| 东丰县| 隆德县| 溧水县| 蓝山县| 都匀市| 绥江县| 凌云县| 甘南县| 灌南县| 新竹县| 习水县| 鸡西市| 右玉县| 鱼台县| 涟源市| 攀枝花市| 江川县| 沙雅县| 榆树市| 佛教| 满城县| 石柱| 盐城市| 隆昌县| 清水河县| 海丰县| 汉中市| 龙陵县| 龙南县| 新宁县| 吴堡县| 眉山市| 申扎县| 正安县| 怀来县| 武乡县| 稷山县| 封开县|