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

vue3.0響應(yīng)式函數(shù)原理詳細(xì)

 更新時(shí)間:2022年02月14日 11:27:45   作者:隱冬  
這篇文章主要介紹了vue3.0響應(yīng)式函數(shù)原理,Vue3的響應(yīng)式系統(tǒng)可以監(jiān)聽(tīng)動(dòng)態(tài)添加的屬性還可以監(jiān)聽(tīng)屬性的刪除操作,以及數(shù)組的索引以及l(fā)ength屬性的修改操作。另外Vue3的響應(yīng)式系統(tǒng)還可以作為模塊單獨(dú)使用。下面更多介紹,需要的小伙伴可以才可以參考一下

前言:

Vue3重寫(xiě)了響應(yīng)式系統(tǒng),和Vue2相比底層采用Proxy對(duì)象實(shí)現(xiàn),在初始化的時(shí)候不需要遍歷所有的屬性再把屬性通過(guò)defineProperty轉(zhuǎn)換成get和set。另外如果有多層屬性嵌套的話只有訪問(wèn)某個(gè)屬性的時(shí)候才會(huì)遞歸處理下一級(jí)的屬性所以Vue3中響應(yīng)式系統(tǒng)的性能要比Vue2好。

接下來(lái)我們自己實(shí)現(xiàn)Vue3響應(yīng)式系統(tǒng)的核心函數(shù)(reactive/ref/toRefs/computed/effect/track/trigger)來(lái)學(xué)習(xí)一下響應(yīng)式原理。

首先我們使用Proxy來(lái)實(shí)現(xiàn)響應(yīng)式中的第一個(gè)函數(shù)reactive。

1.reactive

reactive接收一個(gè)參數(shù),首先要判斷這個(gè)參數(shù)是否是一個(gè)對(duì)象,如果不是直接返回,reactive只能將對(duì)象轉(zhuǎn)換成響應(yīng)式對(duì)象,這是和ref不同的地方。

接著會(huì)創(chuàng)建攔截器對(duì)象handler, 其中抱哈get,set,deleteProperty等攔截方法,最后創(chuàng)建并返回Proxy對(duì)象。

// 判斷是否是一個(gè)對(duì)象
const isObject = val => val !== null && typeof val === 'object'
// 如果是對(duì)象則調(diào)用reactive
const convert= target => isObject(target) ? reactive(target) : target
// 判斷對(duì)象是否存在key屬性
const haOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target, key) => haOwnProperty.call(target, key)

export function reactive (target) {
? ? if (!isObject(target)) {
? ? ? ? // 如果不是對(duì)象直接返回
? ? ? ? return target
? ? }

? ? const handler = {
? ? ? ? get (target, key, receiver) {
? ? ? ? ? ? // 收集依賴
? ? ? ? ? ? const result = Reflect.get(target, key, receiver)
? ? ? ? ? ? // 如果屬性是對(duì)象則需要遞歸處理
? ? ? ? ? ? return convert(result)
? ? ? ? },
? ? ? ? set (target, key, value, receiver) {
? ? ? ? ? ? const oldValue = Reflect.get(target, key, receiver)
? ? ? ? ? ? let result = true;
? ? ? ? ? ? // 需要判斷當(dāng)前傳入的新值和oldValue是否相等,如果不相等再去覆蓋舊值,并且觸發(fā)更新
? ? ? ? ? ? if (oldValue !== value) {
? ? ? ? ? ? ? ? result = Reflect.set(target, key, value, receiver)
? ? ? ? ? ? ? ? // 觸發(fā)更新...
? ? ? ? ? ? }
? ? ? ? ? ? // set方法需要返回布爾值
? ? ? ? ? ? return result;
? ? ? ? },
? ? ? ? deleteProperty (target, key) {
? ? ? ? ? ? // 首先要判斷當(dāng)前target中是否有自己的key屬性
? ? ? ? ? ? // 如果存在key屬性,并且刪除要觸發(fā)更新
? ? ? ? ? ? const hasKey = hasOwn(target, key)
? ? ? ? ? ? const result = Reflect.deleteProperty(target, key)
? ? ? ? ? ? if (hasKey && result) {
? ? ? ? ? ? ? ? // 觸發(fā)更新...
? ? ? ? ? ? }
? ? ? ? ? ? return result;
? ? ? ? }
? ? }
? ? return new Proxy(target, handler)
}

至此reactive函數(shù)就寫(xiě)完了,接著我們來(lái)編寫(xiě)一下收集依賴的過(guò)程。

在依賴收集的過(guò)程會(huì)創(chuàng)建三個(gè)集合,分別是targetMap,depsMap以及dep

其中targetMap是用來(lái)記錄目標(biāo)對(duì)象和字典他使用的是weakMap,key是目標(biāo)對(duì)象,targetMap的值是depsMap, 類型是Map,這里面的key是目標(biāo)對(duì)象的屬性名稱,值是一個(gè)Set集合,集合中存儲(chǔ)的元素是Effect函數(shù)。因?yàn)榭梢远啻握{(diào)用同一個(gè)Effect在Effect訪問(wèn)同一個(gè)屬性,這個(gè)時(shí)候這個(gè)屬性會(huì)收集多次依賴對(duì)應(yīng)多個(gè)Effect函數(shù)。

一個(gè)屬性可以對(duì)應(yīng)多個(gè)Effect函數(shù),觸發(fā)更新的時(shí)候可以通過(guò)屬性找到對(duì)應(yīng)的Effect函數(shù),進(jìn)行執(zhí)行。

我們這里分別來(lái)實(shí)現(xiàn)一下effecttrack兩個(gè)函數(shù)。

effect函數(shù)接收一個(gè)函數(shù)作為參數(shù),我們首先在外面定一個(gè)變量存儲(chǔ)callback, 這樣track函數(shù)就可以訪問(wèn)到callback了。

let activeEffect = null;
export function effect (callback) {
? ? activeEffect = callback;
? ? // 訪問(wèn)響應(yīng)式對(duì)象屬性,收集依賴
? ? callback();
? ? // 依賴收集結(jié)束要置null
? ? activeEffect = null;
}

track函數(shù)接收兩個(gè)參數(shù)目標(biāo)對(duì)象和屬性, 他的內(nèi)部要將target存儲(chǔ)到targetMap中。需要先定義一個(gè)這樣的Map。

let targetMap = new WeakMap()

export function track (target, key) {
? ? // 判斷activeEffect是否存在
? ? if (!activeEffect) {
? ? ? ? return;
? ? }
? ? // depsMap存儲(chǔ)對(duì)象和effect的對(duì)應(yīng)關(guān)系
? ? let depsMap = targetMap.get(target)
? ? // 如果不存在則創(chuàng)建一個(gè)map存儲(chǔ)到targetMap中
? ? if (!depsMap) {
? ? ? ? targetMap.set(target, (depsMap = new Map()))
? ? }
? ? // 根據(jù)屬性查找對(duì)應(yīng)的dep對(duì)象
? ? let dep = depsMap.get(key)
? ? // dep是一個(gè)集合,用于存儲(chǔ)屬性所對(duì)應(yīng)的effect函數(shù)
? ? if (!dep) {
? ? ? ? // 如果不存在,則創(chuàng)建一個(gè)新的集合添加到depsMap中
? ? ? ? depsMap.set(key, (dep = new Set()))
? ? }
? ? dep.add(activeEffect)
}

track是依賴收集的函數(shù)。需要在reactive函數(shù)的get方法中調(diào)用。

get (target, key, receiver) {
? ? // 收集依賴
? ? track(target, key)
? ? const result = Reflect.get(target, key, receiver)
? ? // 如果屬性是對(duì)象則需要遞歸處理
? ? return convert(result)
},

這樣整個(gè)依賴收集就完成了。接著就要實(shí)現(xiàn)觸發(fā)更新,對(duì)應(yīng)的函數(shù)是trigger,這個(gè)過(guò)程和track的過(guò)程正好相反。

trigger函數(shù)接收兩個(gè)參數(shù),分別是target和key。

export function trigger (target, key) {
? ? const depsMap = targetMap.get(target)
? ? // 如果沒(méi)有找到直接返回
? ? if (!depsMap) {
? ? ? ? return;
? ? }
? ? const dep = depsMap.get(key)
? ? if (dep) {
? ? ? ? dep.forEach(effect => {
? ? ? ? ? ? effect()
? ? ? ? })
? ? }
}

trigger函數(shù)要在reactive函數(shù)中的setdeleteProperty中觸發(fā)。

set (target, key, value, receiver) {
? ? const oldValue = Reflect.get(target, key, receiver)
? ? let result = true;
? ? // 需要判斷當(dāng)前傳入的新值和oldValue是否相等,如果不相等再去覆蓋舊值,并且觸發(fā)更新
? ? if (oldValue !== value) {
? ? ? ? result = Reflect.set(target, key, value, receiver)
? ? ? ? // 觸發(fā)更新...
? ? ? ? trigger(target, key)
? ? }
? ? // set方法需要返回布爾值
? ? return result;
},
deleteProperty (target, key) {
? ? // 首先要判斷當(dāng)前target中是否有自己的key屬性
? ? // 如果存在key屬性,并且刪除要觸發(fā)更新
? ? const hasKey = hasOwn(target, key)
? ? const result = Reflect.deleteProperty(target, key)
? ? if (hasKey && result) {
? ? ? ? // 觸發(fā)更新...
? ? ? ? trigger(target, key)
? ? }
? ? return result;
}

2.ref

ref接收一個(gè)參數(shù)可以是原始值也可以是一個(gè)對(duì)象,如果傳入的是對(duì)象并且是ref創(chuàng)建的對(duì)象則直接返回,如果是普通對(duì)象則調(diào)用reactive來(lái)創(chuàng)建響應(yīng)式對(duì)象,否則創(chuàng)建一個(gè)只有value屬性的響應(yīng)式對(duì)象。

export function ref (raw) {
? ? // 判斷raw是否是ref創(chuàng)建的對(duì)象,如果是直接返回
? ? if (isObject(raw) && raw.__v__isRef) {
? ? ? ? return raw
? ? }

? ? // 之前已經(jīng)定義過(guò)convert函數(shù),如果參數(shù)是對(duì)象就會(huì)調(diào)用reactive函數(shù)創(chuàng)建響應(yīng)式
? ? let value = convert(raw);

? ? const r = {
? ? ? ? __v__isRef: true,
? ? ? ? get value () {
? ? ? ? ? ? track(r, 'value')
? ? ? ? ? ? return value
? ? ? ? },
? ? ? ? set value (newValue) {
? ? ? ? ? ? // 判斷新值和舊值是否相等
? ? ? ? ? ? if (newValue !== value) {
? ? ? ? ? ? ? ? raw = newValue
? ? ? ? ? ? ? ? value = convert(raw)
? ? ? ? ? ? ? ? // 觸發(fā)更新
? ? ? ? ? ? ? ? trigger(r, 'value')
? ? ? ? ? ? }
? ? ? ? }
? ? }

? ? return r
}

3.toRefs

toRefs接收reactive函數(shù)返回的響應(yīng)式對(duì)象,如果不是響應(yīng)式對(duì)象則直接返回。將傳入對(duì)象的所有屬性轉(zhuǎn)換成一個(gè)類似ref返回的對(duì)象將準(zhǔn)換后的屬性掛載到一個(gè)新的對(duì)象上返回。

export function toRefs (proxy) {
? ? // 如果是數(shù)組創(chuàng)建一個(gè)相同長(zhǎng)度的數(shù)組,否則返回一個(gè)空對(duì)象
? ? const ret = proxy instanceof Array ? new Array(proxy.length) : {}

? ? for (const key in proxy) {
? ? ? ? ret[key] = toProxyRef(proxy, key)
? ? }

? ? return ret;
}

function toProxyRef (proxy, key) {
? ? const r = {
? ? ? ? __v__isRef: true,
? ? ? ? get value () { // 這里已經(jīng)是響應(yīng)式對(duì)象了,所以不需要再收集依賴了
? ? ? ? ? ? return proxy[key]
? ? ? ? },
? ? ? ? set value (newValue) {
? ? ? ? ? ? proxy[key] = newValue
? ? ? ? }
? ? }
? ? return r
}

toRefs的作用其實(shí)是將reactive中的每個(gè)屬性都變成響應(yīng)式的。reactive方法會(huì)創(chuàng)建一個(gè)響應(yīng)式的對(duì)象,但是如果將reactive返回的對(duì)象進(jìn)行解構(gòu)使用就不再

是響應(yīng)式了,toRefs的作用就是支持解構(gòu)之后仍舊為響應(yīng)式。

4.computed

接著再來(lái)模擬一下computed函數(shù)的內(nèi)部實(shí)現(xiàn)

computed需要接收一個(gè)有返回值的函數(shù)作為參數(shù),這個(gè)函數(shù)的返回值就是計(jì)算屬性的值,需要監(jiān)聽(tīng)函數(shù)內(nèi)部響應(yīng)式數(shù)據(jù)的變化,最后將函數(shù)執(zhí)行的結(jié)果返回。

export function computed (getter) {
? ? const result = ref()

? ? effect(() => (result.value = getter()))

? ? return result
}

computed函數(shù)會(huì)通過(guò)effect監(jiān)聽(tīng)getter內(nèi)部響應(yīng)式數(shù)據(jù)的變化,因?yàn)樵趀ffect中執(zhí)行g(shù)etter的時(shí)候訪問(wèn)響應(yīng)式數(shù)據(jù)的屬性會(huì)去收集依賴,當(dāng)數(shù)據(jù)變化會(huì)重新執(zhí)行effect函數(shù),將getter的結(jié)果再存儲(chǔ)到result中。

到此這篇關(guān)于vue3.0響應(yīng)式函數(shù)原理詳細(xì)的文章就介紹到這了,更多相關(guān)vue3.0響應(yīng)式函數(shù)原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue3如何實(shí)現(xiàn)PDF文件在線預(yù)覽功能

    vue3如何實(shí)現(xiàn)PDF文件在線預(yù)覽功能

    PDF文件在線預(yù)覽的功能相信大家都是有遇到過(guò)的,下面這篇文章主要給大家介紹了關(guān)于vue3如何實(shí)現(xiàn)PDF文件在線預(yù)覽功能的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • 如何使用vuejs實(shí)現(xiàn)更好的Form validation?

    如何使用vuejs實(shí)現(xiàn)更好的Form validation?

    如何使用vuejs實(shí)現(xiàn)更好的Form validation?這篇文章主要介紹了vue-form插件的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • vue后臺(tái)系統(tǒng)管理項(xiàng)目之角色權(quán)限分配管理功能(示例詳解)

    vue后臺(tái)系統(tǒng)管理項(xiàng)目之角色權(quán)限分配管理功能(示例詳解)

    這篇文章主要介紹了vue后臺(tái)系統(tǒng)管理項(xiàng)目-角色權(quán)限分配管理功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • Vue3中的Refs和Ref詳情

    Vue3中的Refs和Ref詳情

    這篇文章主要介紹了Vue3中的Refs和Ref,文章圍繞Vue3中的Refs和Ref得相關(guān)資料應(yīng)用舉例煩人方式展開(kāi)詳細(xì)內(nèi)容,需要的朋友可以參考一下
    2021-11-11
  • vue如何從后臺(tái)下載.zip壓縮包文件

    vue如何從后臺(tái)下載.zip壓縮包文件

    這篇文章主要介紹了vue如何從后臺(tái)下載.zip壓縮包文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue3?ref獲取組件實(shí)例詳細(xì)圖文教程

    vue3?ref獲取組件實(shí)例詳細(xì)圖文教程

    在Vue3中可以使用ref函數(shù)來(lái)創(chuàng)建一個(gè)響應(yīng)式的變量,通過(guò)將ref函數(shù)應(yīng)用于一個(gè)組件實(shí)例,我們可以獲取到該組件的實(shí)例對(duì)象,這篇文章主要給大家介紹了關(guān)于vue3?ref獲取組件實(shí)例的詳細(xì)圖文教程,需要的朋友可以參考下
    2023-10-10
  • vue封裝公共方法的實(shí)現(xiàn)代碼

    vue封裝公共方法的實(shí)現(xiàn)代碼

    這篇文章給大家介紹了vue封裝公共方法的實(shí)現(xiàn),文章中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-01-01
  • vue中如何自定義右鍵菜單詳解

    vue中如何自定義右鍵菜單詳解

    這篇文章主要給大家介紹了關(guān)于vue中如何自定義右鍵菜單的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • vue中el-cascader三級(jí)聯(lián)動(dòng)懶加載回顯問(wèn)題解決

    vue中el-cascader三級(jí)聯(lián)動(dòng)懶加載回顯問(wèn)題解決

    本文主要介紹了vue中el-cascader三級(jí)聯(lián)動(dòng)懶加載回顯問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • vue實(shí)現(xiàn)的仿淘寶購(gòu)物車功能詳解

    vue實(shí)現(xiàn)的仿淘寶購(gòu)物車功能詳解

    這篇文章主要介紹了vue實(shí)現(xiàn)的仿淘寶購(gòu)物車功能,結(jié)合完整實(shí)例形式較為詳細(xì)的分析了vue.js仿淘寶購(gòu)物車功能的具體樣式、功能相關(guān)實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2019-01-01

最新評(píng)論

河东区| 舞阳县| 和田市| 大宁县| 从化市| 香港| 库车县| 满洲里市| 涪陵区| 万源市| 石河子市| 天峨县| 宜川县| 嘉黎县| 化隆| 商都县| 翁牛特旗| 石景山区| 古交市| 沙雅县| 县级市| 进贤县| 南平市| 武平县| 洛隆县| 政和县| 兴仁县| 尤溪县| 林周县| 苏尼特左旗| 宝坻区| 宝应县| 乌什县| 东乌| 许昌市| 新营市| 吉林市| 内江市| 嵊州市| 珠海市| 平江县|