欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析一下Vue3的響應式原理

 更新時間:2022年08月11日 14:10:04   作者:王岳  
這篇文章主要通過示例和大家一起淺析一下Vue3的響應式原理,文中的示例代碼講解詳細,對我們學習Vue3有一定幫助,需要的可以參考一下

Proxy

Vue3 的響應式原理依賴了 Proxy 這個核心 API,通過 Proxy 可以劫持對象的某些操作。

const?obj?=?{?a:?1?};
const?p?=?new?Proxy(obj,?{
??get(target,?property,?receiver)?{
????console.log("get");
????return?Reflect.get(target,?property,?receiver);
??},
??set(target,?property,?value,?receiver)?{
????console.log("set");
????return?Reflect.set(target,?property,?receiver);
??},
??has(target,?prop)?{
????console.log("has");
????return?Reflect.has(target,?prop);
??},
??deleteProperty(target,?prop)?{
????console.log("deleteProperty");
????return?Reflect.deleteProperty(target,?prop);
??},
});

p.a;?//?輸出?-->?get
p.a?=?2;?//?輸出?-->?set
"a"?in?p;?//?輸出?-->?has
delete?p.a;?//?輸出?-->?deleteProperty

如上例子,我們用 Proxy 代理了 Obj 對象的屬性訪問、屬性賦值、in 操作符、delete 的操作,并進行 console.log 輸出。

Reflect

Reflect 是與 Proxy 搭配使用的一個 API,當我們劫持了某些操作時,如果需要再把這些操作反射回去,那么就需要 Reflect 這個 API。

由于我們攔截了對象的操作,所以這些操作該有的功能都喪失了,例如,訪問屬性 p.a 應該得到 a 屬性的值,但此時卻不會有任何結果,如果我們還想擁有攔截之前的功能,那我們就需要用 Reflect 反射回去。

const?obj?=?{?a:?1?};
const?p?=?new?Proxy(obj,?{
??get(target,?property,?receiver)?{
????console.log("get");
????return?Reflect.get(target,?property,?receiver);
??},
??set(target,?property,?value,?receiver)?{
????console.log("set");
????return?Reflect.set(target,?property,?receiver);
??},
??has(target,?prop)?{
????console.log("has");
????return?Reflect.has(target,?prop);
??},
??deleteProperty(target,?prop)?{
????console.log("deleteProperty");
????return?Reflect.deleteProperty(target,?prop);
??},
});

舉個例子

以下全文我們都會通過這個例子來講述 Vue3 響應式的原理。

<div?id="app"></div>

<script>
??//?創(chuàng)建一個響應式對象
??const?state?=?reactive({?counter:?1?});

??//?立即運行一個函數(shù),當響應式對象的屬性發(fā)生改變時重新執(zhí)行。
??effect(()?=>?{
????document.querySelector("#app").innerHTML?=?state.counter;
??});

??//?2s?后視圖更新
??setTimeout(()?=>?{
????state.counter?+=?1;
??},?2000);
</script>

我們用 reactive 創(chuàng)建了一個響應式對象 state,并調用了 effect 方法,該方法接受一個副作用函數(shù),effect 的執(zhí)行會立即調用副作用函數(shù),并將 state.counter 賦值給 #app.innerHTML;兩秒后,state.counter += 1,此時,effect 的副作用函數(shù)會重新執(zhí)行,頁面也會變成 2.

內部的執(zhí)行過程大概如下圖所示:

  • 調用 reactive() 返回一個 Proxy 代理對象,并劫持對象的 get 與 set 操作
  • 調用 effect() 方法時,會訪問屬性 state.counter,此時會觸發(fā) proxy 的 get 操作。
  • get 方法會調用 track() 進行依賴收集;建立一個對象(state)、屬性(counter)、effect 副作用函數(shù)的依賴關系;
  • set 方法會調用 trigger() 進行依賴更新;通過對象(state)與屬性(coutner)找到對應的 effect 副作用函數(shù),然后重新執(zhí)行。

reactive

reactive 會返回如下一個 Proxy 對象

const?reactive?=?(target)?=>?{
??return?new?Proxy(target,?{
????get(target,?key,?receiver)?{
??????const?res?=?Reflect.get(target,?key,?receiver);

??????track(target,?key);?//?收集依賴

??????if?(isObject(res))?{
????????//?如果當前獲取的屬性值是一個對象,則繼續(xù)將為此對象創(chuàng)建?Proxy?代理
????????return?reactive(res);
??????}

??????return?res;
????},

????set(target,?key,?value,?receiver)?{
??????Reflect.set(target,?key,?value,?receiver);
??????trigger(target,?key);?//?依賴更新
????},
??});
};

effect

let?activeEffect;
function?effect(fn)?{
??const?_effect?=?function?reactiveEffect()?{
????activeEffect?=?_effect;
????fn();
??};

??_effect();
}

首先定義全局的 activeEffect,它永遠指向當前正在執(zhí)行的 effect 副作用函數(shù)。effect 為 fn 創(chuàng)建一個內部的副作用函數(shù),然后立即執(zhí)行,此時會觸發(fā)對象的 get 操作,調用 track() 方法。

effect(()?=>?{
??// effect 的立即執(zhí)行會訪問 state.counter,觸發(fā)了對象的 get 操作。
??document.querySelector("#app").innerHTML?=?state.counter;
});

track

track 會建立一個 對象(state) => 屬性(counter) => effect 的一個依賴關系

const?targetMap?=?new?WeakMap();
function?track(target,?key)?{
??if?(!activeEffect)?{
????return;
??}

??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()));
??}

??if?(!dep.has(activeEffect))?{
????dep.add(activeEffect);
??}
}

執(zhí)行完成成后我們得到一個如下的數(shù)據(jù)結構:

[?//?map?集合
??{
????key:?{counter:?1}?//?state?對象,
????value:?[?//?map?集合
??????{
????????key:?"counter",
????????value:?[?//?set
??????????function?reactiveEffect()?{}?//?effect?副作用函數(shù)
????????],
??????}
????],
??},
];

注意:當我們調用 effect 時,會將當前的副作用函數(shù)賦值給全局的 activeEffect,所以此時我們可以正確關聯(lián)其依賴。

trigger

當我們給 state.counter 賦值的時候就會觸發(fā)代理對象的 set 操作,從而調用 trigger 方法

setTimeout(()?=>?{
??//?給?counter?屬性賦值會觸發(fā)?set?操作
??state.counter?+=?1;
},?2000);
function?trigger(target,?key)?{
??const?depsMap?=?targetMap.get(target);
??if?(!depsMap)?return;

??const?effects?=?depsMap.get(key);
??effects?&&?effects.forEach((effect)?=>?effect());
}

以上就是淺析一下Vue3的響應式原理的詳細內容,更多關于Vue3響應式原理的資料請關注腳本之家其它相關文章!

相關文章

  • Vue自定義屬性實例分析

    Vue自定義屬性實例分析

    這篇文章主要介紹了Vue自定義屬性,結合實例形式分析了vue.js自定義屬性相關原理、實現(xiàn)方法及操作注意事項,需要的朋友可以參考下
    2019-02-02
  • vue頁面批量引入組件的操作代碼

    vue頁面批量引入組件的操作代碼

    這篇文章主要介紹了vue頁面批量引入組件,本文結合示例代碼給大家講解的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-12-12
  • vue.js的簡單自動求和計算實例

    vue.js的簡單自動求和計算實例

    今天小編就為大家分享一篇vue.js的簡單自動求和計算實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • ajax請求+vue.js渲染+頁面加載的示例

    ajax請求+vue.js渲染+頁面加載的示例

    下面小編就為大家分享一篇ajax請求+vue.js渲染+頁面加載的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • 詳解如何從零開始搭建Express+Vue開發(fā)環(huán)境

    詳解如何從零開始搭建Express+Vue開發(fā)環(huán)境

    這篇文章主要介紹了詳解如何從零開始搭建Express+Vue開發(fā)環(huán)境,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • vuejs項目打包之后的首屏加載優(yōu)化及打包之后出現(xiàn)的問題

    vuejs項目打包之后的首屏加載優(yōu)化及打包之后出現(xiàn)的問題

    這篇文章主要介紹了vuejs項目打包之后的首屏加載優(yōu)化及打包之后可能出現(xiàn)的問題,需要的朋友可以參考下
    2018-04-04
  • 在Vue中使用Echarts+封裝

    在Vue中使用Echarts+封裝

    這篇文章主要介紹了在Vue中使用Echarts++封裝,需要的朋友可以參考下
    2023-11-11
  • Vue-less的使用和deep深度選擇器詳解

    Vue-less的使用和deep深度選擇器詳解

    這篇文章主要介紹了Vue-less的使用和deep深度選擇器,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 詳解Vue-基本標簽和自定義控件

    詳解Vue-基本標簽和自定義控件

    本篇文章主要介紹了Vue-基本標簽和自定義控件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • SpringBoot+Vue3實現(xiàn)上傳文件功能

    SpringBoot+Vue3實現(xiàn)上傳文件功能

    這篇文章主要介紹了SpringBoot+Vue3實現(xiàn)上傳文件功能,本文結合示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-01-01

最新評論