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

Vue利用廣度優(yōu)先搜索實(shí)現(xiàn)watch

 更新時(shí)間:2023年08月04日 10:04:36   作者:前端胖頭魚(yú)  
這篇文章主要為大家學(xué)習(xí)介紹了Vue如何利用廣度優(yōu)先搜索實(shí)現(xiàn)watch(有意思),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

前言

通過(guò)前面幾篇文章,我們對(duì)Vue3中的響應(yīng)式設(shè)計(jì)有了初步的了解。

這一篇我們?cè)囍鴮?shí)現(xiàn)一個(gè)watch

1. 兩種watch的基本用法

1.1 通過(guò)函數(shù)回調(diào)監(jiān)聽(tīng)數(shù)據(jù)

最基本的用法是給watch指定一個(gè)回調(diào)函數(shù)并返回你想要監(jiān)聽(tīng)的響應(yīng)式數(shù)據(jù)

const?state1?=?reactive({
??name:?'前端胖頭魚(yú)',
??age:?100
})
watch(()?=>?state1.age,?()?=>?{
??console.log('state1的age發(fā)生變化了',?state1.age)
})
state1.age?=?200
setTimeout(()?=>?{
??state1.age?=?300
},?500)

1.2 直接監(jiān)聽(tīng)一個(gè)對(duì)象

還可以直接監(jiān)聽(tīng)一個(gè)響應(yīng)式對(duì)象來(lái)觀測(cè)它的變化。

const?state1?=?reactive({
??name:?'前端胖頭魚(yú)',
??age:?100,
??children:?{
????name:?'胖小魚(yú)',
????age:?10
??}
})
watch(state1,?()?=>?{
??console.log('state1發(fā)生變化了',?state1)
})
state1.age?=?200
setTimeout(()?=>?{
??state1.children.age?=?100
},?500)

2. 實(shí)現(xiàn)watch最核心的點(diǎn)

其實(shí)watch的底層實(shí)現(xiàn)非常簡(jiǎn)單,和computed一樣都需要借助任務(wù)調(diào)度。

簡(jiǎn)單來(lái)說(shuō)就是感知數(shù)據(jù)的變化,數(shù)據(jù)發(fā)生了變化就執(zhí)行對(duì)應(yīng)的回調(diào),那么怎么感知呢?

const?state?=?reactive({
??name:?'前端胖頭魚(yú)'
})
useEffect(()?=>?{
??//?原本state發(fā)生變化之后,應(yīng)該執(zhí)行這里
??console.log(state.name)
},?{
??//?但是指定scheduler之后,會(huì)執(zhí)行這里
??scheduler?()?{
????console.log('state變化了')
??}
})
state.name?=?'胖小魚(yú)'

聰明的你肯定也猜到了,scheduler不就是天然感知數(shù)據(jù)的變化的工具嗎?

沒(méi)錯(cuò),watch的實(shí)現(xiàn)少不了它,來(lái)吧,搞起?。?!

3. 支持兩種使用方式

3.1 支持回調(diào)函數(shù)形式

const?watch?=?(source,?cb)?=>?{
??effect(source,?{
????scheduler?()?{
??????cb()
????},
??})
}
//?測(cè)試一波
const?state?=?reactive({
??name:?'前端胖頭魚(yú)',
})
watch(()?=>?state.name,?()?=>?{
??console.log('state.name發(fā)生了變化',?state.name)
})
state.name?=?'胖小魚(yú)'

3.2 支持直接傳遞響應(yīng)式對(duì)象

不錯(cuò)哦!第一種方式已經(jīng)初步實(shí)現(xiàn)了,接下來(lái)搞第二種。

第二種直接傳入響應(yīng)式對(duì)象的方式和第一種傳入回調(diào)函數(shù)并指向響應(yīng)式數(shù)據(jù)的區(qū)別是什么?

在于我們需要手動(dòng)遍歷這個(gè)響應(yīng)式對(duì)象使得它的任意屬性發(fā)生變化我們都能感知到。

3.3 廣度優(yōu)先搜索遍歷深層嵌套的屬性

此時(shí)就到了這篇文章裝逼(額~~)的點(diǎn)了。如果想訪問(wèn)一個(gè)深層嵌套對(duì)象的所有屬性,最常見(jiàn)的做法就是遞歸。

如果你想在面試的過(guò)程中秀一波,我覺(jué)得使用廣度優(yōu)先搜索是個(gè)不錯(cuò)的主意(狗頭臉),代碼也非常簡(jiǎn)單,就不詳細(xì)解釋了。

如果您對(duì)廣度優(yōu)先搜索和深度優(yōu)先搜索感興趣歡迎在評(píng)論區(qū)留言,我會(huì)單獨(dú)寫(xiě)一篇文章來(lái)講它。

?const?bfs?=?(obj,?callback)?=>?{
??const?queue?=?[?obj?]
??while?(queue.length)?{
????const?top?=?queue.shift()
????if?(top?&&?typeof?top?===?'object')?{
??????for?(let?key?in?top)?{
????????//?讀取操作出發(fā)getter,完成依賴搜集
????????queue.push(top[?key?])
??????}
????}?else?{
??????callback?&&?callback(top)
????}
??}
}
const?obj?=?{
??name:?'前端胖頭魚(yú)',
??age:?100,
??obj2:?{
????name:?'胖小魚(yú)',
????age:?10,
????obj3:?{
??????name:?'胖小小魚(yú)',
??????age:?1,
????}
??},
}
bfs(obj,?(value)?=>?{
??console.log(value)
})

我們已經(jīng)能夠讀取深層嵌套對(duì)象的任意屬性了,接下來(lái)繼續(xù)完善watch方法

const?watch?=?(source,?cb)?=>?{
??let?getter
??//?處理傳回調(diào)的方式
??if?(typeof?source?===?"function")?{
????getter?=?source
??}?else?{
????//?封裝成讀取source對(duì)象的函數(shù),觸發(fā)任意一個(gè)屬性的getter,進(jìn)而搜集依賴
????getter?=?()?=>?bfs(source)
??}
??const?effectFn?=?effect(getter,?{
????scheduler()?{
??????cb()
????}
??})
}
//?測(cè)試一波
const?state?=?reactive({
??name:?"前端胖頭魚(yú)",
??age:?100,
??obj2:?{
????name:?"胖小魚(yú)",
????age:?10,
??},
})
watch(state,?()?=>?{
??console.log("state發(fā)生變化了");
});

看來(lái)還是有不少坑?。‰m然我們實(shí)現(xiàn)了n層嵌套對(duì)象屬性的讀?。ɡ碚撋纤械膶傩愿淖兌紤?yīng)該觸發(fā)回調(diào)),但是state.obj2.name = 'yyyy'卻沒(méi)有被感知到,為什么呢?

3.4 淺響應(yīng)與深響應(yīng)

回顧一下reactive函數(shù),你會(huì)發(fā)現(xiàn),當(dāng)value本身也是一個(gè)對(duì)象的時(shí)候,我們并不會(huì)使value也變成一個(gè)響應(yīng)式數(shù)據(jù)。

所以哪怕我們通過(guò)bfs方法遍歷了該對(duì)象的所有屬性,也僅僅是第一層的key具有了響應(yīng)式效果而已。

//?統(tǒng)一對(duì)外暴露響應(yīng)式函數(shù)
function?reactive(state)?{
??return?new?Proxy(state,?{
????get(target,?key)?{
??????const?value?=?target[key]
??????//?搜集key的依賴
??????//?如果value本身是一個(gè)對(duì)象,對(duì)象下的屬性將不具有響應(yīng)式
??????track(target,?key)?
??????return?value;
????},
????set(target,?key,?newValue)?{
??????//?console.log(`set?${key}:?${newValue}`)
??????//?設(shè)置屬性值
??????target[key]?=?newValue
??????trigger(target,?key)
????},
??})
}

解決辦法也很簡(jiǎn)單,是對(duì)象的情況下再給他reactive一次就好了。

//?統(tǒng)一對(duì)外暴露響應(yīng)式函數(shù)
function?reactive(state)?{
??return?new?Proxy(state,?{
????get(target,?key)?{
??????const?value?=?target[key]
??????//?搜集key的依賴
??????//?如果value本身是一個(gè)對(duì)象,對(duì)象下的屬性將不具有響應(yīng)式
??????track(target,?key)?
??????//?如果是對(duì)象,再使其也變成一個(gè)響應(yīng)式數(shù)據(jù)
??????if?(typeof?value?===?"object"?&&?value?!==?null)?{
????????return?reactive(value);
??????}
??????return?value;
????},
????set(target,?key,?newValue)?{
??????//?console.log(`set?${key}:?${newValue}`)
??????//?設(shè)置屬性值
??????target[key]?=?newValue
??????trigger(target,?key)
????},
??})
}

最后再回到前面的例子,你會(huì)發(fā)現(xiàn)我們成功了!!!

4. watch的新值和舊值

到目前為止,我們實(shí)現(xiàn)了watch最基本的功能,感知其數(shù)據(jù)的變化并執(zhí)行對(duì)應(yīng)的回調(diào)。

接下來(lái)我們?cè)賹?shí)現(xiàn)一個(gè)基礎(chǔ)功能:在回調(diào)函數(shù)中獲取新值與舊值。

watch(state,?(newVal,?oldVal)?=>?{
??//?xxx
})

新值和舊值主要在于獲取時(shí)機(jī)不一樣,獲取方式確實(shí)一模一樣的,執(zhí)行effectFn即可

const?watch?=?(source,?cb)?=>?{
??let?getter
??let?oldValue
??let?newValue
??//?處理傳回調(diào)的方式
??if?(typeof?source?===?"function")?{
????getter?=?source
??}?else?{
????getter?=?()?=>?bfs(source)
??}
??const?effectFn?=?effect(getter,?{
????lazy:?true,
????scheduler()?{
??????//?變化后獲取新值
??????newValue?=?effectFn()
??????cb(newValue,?oldValue)
??????//?執(zhí)行回調(diào)后將新值設(shè)置為舊值
??????oldValue?=?newValue
????}
??})
??//?第一次執(zhí)行獲取值
??oldValue?=?effectFn()
}

測(cè)試一波

const?state?=?reactive({
??name:?"前端胖頭魚(yú)",
??age:?100,
??obj2:?{
????name:?"胖小魚(yú)",
????age:?10,
??},
})
watch(()?=>?state.name,?(newValue,?oldValue)?=>?{
??console.log("state.name",?{?newValue,?oldValue?})
})
state.name?=?'111'

5. 支持立即調(diào)用時(shí)機(jī)

最后再實(shí)現(xiàn)立即調(diào)用時(shí)機(jī)immediate,watch就大功告成啦!

const?watch?=?(source,?cb,?options?=?{})?=>?{
??let?getter
??let?oldValue
??let?newValue
??//?處理傳回調(diào)的方式
??if?(typeof?source?===?"function")?{
????getter?=?source
??}?else?{
????getter?=?()?=>?bfs(source)
??}
??const?job?=?()?=>?{
????//?變化后獲取新值
????newValue?=?effectFn()
????cb(newValue,?oldValue)
????//?執(zhí)行回調(diào)后將新值設(shè)置為舊值
????oldValue?=?newValue
??}
??const?effectFn?=?effect(getter,?{
????lazy:?true,
????scheduler()?{
??????job()
????}
??})
??//?如果指定了立即執(zhí)行,便執(zhí)行第一次
??if?(options.immediate)?{
????job()
??}?else?{
????oldValue?=?effectFn()
??}
}
watch(()?=>?state.name,?(newValue,?oldValue)?=>?{
??console.log("state.name",?{?newValue,?oldValue?});
},?{?immediate:?true?});

通過(guò)判斷immediate是否為true來(lái)決定是否一開(kāi)始就執(zhí)行cb回調(diào),且第一次回調(diào)的舊值oldValue應(yīng)該為undefined

以上就是Vue利用廣度優(yōu)先搜索實(shí)現(xiàn)watch的詳細(xì)內(nèi)容,更多關(guān)于Vue watch的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于vue+openlayer實(shí)現(xiàn)地圖聚合和撒點(diǎn)效果

    基于vue+openlayer實(shí)現(xiàn)地圖聚合和撒點(diǎn)效果

    Openlayers 是一個(gè)模塊化、高性能并且功能豐富的WebGIS客戶端的JavaScript包,用于顯示地圖及空間數(shù)據(jù),并與之進(jìn)行交互,具有靈活的擴(kuò)展機(jī)制,本文給大家介紹vue+openlayer實(shí)現(xiàn)地圖聚合效果和撒點(diǎn)效果,感興趣的朋友一起看看吧
    2021-09-09
  • vue3.0父?jìng)鹘o子的值不隨父組件改變而改變問(wèn)題及解決

    vue3.0父?jìng)鹘o子的值不隨父組件改變而改變問(wèn)題及解決

    這篇文章主要介紹了vue3.0父?jìng)鹘o子的值不隨父組件改變而改變問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue中props用法介紹

    Vue中props用法介紹

    這篇文章主要給大家分享的是 Vue中props用法介紹,? 在Vue中通過(guò)props,可以將原本孤立的組件串聯(lián)起來(lái),也就是可以子組件可以接收父組件傳遞過(guò)來(lái)的data,下面我們一起進(jìn)入文章看看內(nèi)容的詳細(xì)介紹吧,需要的朋友也可以參考一下
    2021-11-11
  • vue下axios攔截器token刷新機(jī)制的實(shí)例代碼

    vue下axios攔截器token刷新機(jī)制的實(shí)例代碼

    這篇文章主要介紹了vue下axios攔截器token刷新機(jī)制的實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • vue.js基于ElementUI封裝了CRUD的彈框組件

    vue.js基于ElementUI封裝了CRUD的彈框組件

    這篇文章主要介紹了vue.js基于ElementUI封裝了CRUD的彈框組件,問(wèn)咋會(huì)給你圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,感興趣的小伙伴可以參考一下
    2022-07-07
  • 用Vue封裝導(dǎo)航欄組件

    用Vue封裝導(dǎo)航欄組件

    這篇文章主要為大家詳細(xì)介紹了用Vue封裝導(dǎo)航欄組件的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • vue init webpack myproject構(gòu)建項(xiàng)目 ip不能訪問(wèn)的解決方法

    vue init webpack myproject構(gòu)建項(xiàng)目 ip不能訪問(wèn)的解決方法

    下面小編就為大家分享一篇vue init webpack myproject構(gòu)建項(xiàng)目 ip不能訪問(wèn)的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • vue 使用axios 數(shù)據(jù)請(qǐng)求第三方插件的使用教程詳解

    vue 使用axios 數(shù)據(jù)請(qǐng)求第三方插件的使用教程詳解

    這篇文章主要介紹了vue 使用axios 數(shù)據(jù)請(qǐng)求第三方插件的使用 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 詳解vue computed的緩存實(shí)現(xiàn)原理

    詳解vue computed的緩存實(shí)現(xiàn)原理

    這篇文章主要介紹了vue computed的緩存實(shí)現(xiàn)原理,幫助大家更好的理解和學(xué)習(xí)使用vue,感興趣的朋友可以了解下
    2021-04-04
  • Vue+Element-UI中el-table動(dòng)態(tài)合并單元格:span-method方法代碼詳解

    Vue+Element-UI中el-table動(dòng)態(tài)合并單元格:span-method方法代碼詳解

    el-table是element-ui提供的表格組件,可以用于展示和操作數(shù)據(jù),這篇文章主要給大家介紹了關(guān)于Vue+Element-UI中el-table動(dòng)態(tài)合并單元格:span-method方法的相關(guān)資料,需要的朋友可以參考下
    2023-09-09

最新評(píng)論

区。| 三台县| 濮阳县| 特克斯县| 南和县| 库伦旗| 新干县| 洞头县| 连平县| 桐梓县| 蚌埠市| 宜阳县| 崇明县| 苗栗市| 安乡县| 金门县| 岳池县| 黄冈市| 孟州市| 阳泉市| 上林县| 博客| 左云县| 临湘市| 杂多县| 凭祥市| 肇东市| 汤原县| 临安市| 云梦县| 韩城市| 通河县| 井冈山市| 察隅县| 洪洞县| 政和县| 永新县| 常州市| 四子王旗| 肃南| 凉山|