本篇內(nèi)容介紹了“Vue3偵聽(tīng)器怎么應(yīng)用”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)建站堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的宕昌網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
前面我們聊到計(jì)算屬性,它可以自動(dòng)計(jì)算并緩存響應(yīng)式數(shù)據(jù)的值。而如果我們僅需要在響應(yīng)式數(shù)據(jù)變化時(shí),執(zhí)行一些預(yù)設(shè)的操作,就可以使用watch
偵聽(tīng)器。我們還是先來(lái)實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的例子,然后來(lái)一點(diǎn)一點(diǎn)擴(kuò)充它。
const data = {foo: 1} const obj = reactive(data) watch(obj, () => { console.log('obj已改變') })
在這個(gè)例子中,我們使用了watch
偵聽(tīng)器,當(dāng)obj
的屬性被改變時(shí),控制臺(tái)應(yīng)該會(huì)打印出obj已改變
?;谇懊嫖覀儗?duì)計(jì)算屬性的實(shí)現(xiàn),這里我們已經(jīng)有了一個(gè)大概的思路。把watch
視為響應(yīng)式對(duì)象的副作用函數(shù),當(dāng)響應(yīng)式對(duì)象改變時(shí),觸發(fā)執(zhí)行該副作用函數(shù)。
想要觸發(fā)副作用函數(shù),必須先收集它,還記得副作用函數(shù)是如何收集的嗎?對(duì),當(dāng)響應(yīng)式數(shù)據(jù)被get
時(shí),收集副作用函數(shù)。所以首先,我們需要讓watch
被響應(yīng)式對(duì)象收集到。
function watch(getter, cb) { effect( () => getter.foo ) }
接著,我們還需要讓我們預(yù)設(shè)的方法被執(zhí)行。當(dāng)響應(yīng)式數(shù)據(jù)被set
時(shí),觸發(fā)副作用函數(shù)。這里我們想觸發(fā)的是cb
這個(gè)傳入的回調(diào)函數(shù),這里我們就又能用到實(shí)現(xiàn)計(jì)算屬性時(shí)的調(diào)度器了,當(dāng)調(diào)度器存在時(shí),set
觸發(fā)的trigger
會(huì)先執(zhí)行調(diào)度器中的函數(shù)。
function watch(getter, cb) { effect( () => getter.foo, { scheduler() { cb() } } ) }
一個(gè)簡(jiǎn)單的偵聽(tīng)器已經(jīng)完成了!這里我們?yōu)榱撕?jiǎn)單,把功能寫死了,僅支持對(duì)obj.foo
的偵聽(tīng)。接下來(lái),我們就要想想,如何實(shí)現(xiàn)對(duì)響應(yīng)式對(duì)象的任意屬性進(jìn)行偵聽(tīng)?
按照前面的思路,想要實(shí)現(xiàn)對(duì)響應(yīng)式對(duì)象的任意屬性的偵聽(tīng),就需要我們get
到該對(duì)象的每一個(gè)屬性,這就需要我們對(duì)響應(yīng)式對(duì)象進(jìn)行一次遞歸遍歷。
function traverse(value, seen = new Set()) { // (1) if(typeof value !== 'object' || value === null || seen.has(value)) return seen.add(value) for(const key in value) { traverse(value[key], seen) } return value }
為了避免遞歸遍歷對(duì)象時(shí),循環(huán)引用造成的死循環(huán),我們?cè)?code>(1)處創(chuàng)建了Set
,當(dāng)重復(fù)出現(xiàn)相同的對(duì)象時(shí),直接返回。
在Vue3中,我們不能直接偵聽(tīng)響應(yīng)式對(duì)象的屬性值。如果需要偵聽(tīng)響應(yīng)式對(duì)象的屬性值,就需要一個(gè)getter
函數(shù),讓偵聽(tīng)器能被響應(yīng)式對(duì)象收集到。
const data = { foo: 1 } const obj = reactive(data) watch( () => obj.foo, () => { console.log('obj.foo已改變') })
指定了屬性就意味著,當(dāng)前的偵聽(tīng)器僅會(huì)被指定的屬性觸發(fā),就無(wú)需遞歸遍歷整個(gè)響應(yīng)式對(duì)象了。
function watch(getter, cb) { if(typeof getter !== 'function') getter = traverse(getter) // (2) effect( () => getter(), { scheduler() { cb() } } ) }
在(2)處,我們?cè)黾恿艘粋€(gè)判斷,如果傳入的已經(jīng)是getter
函數(shù),我們直接使用,如果不是getter
函數(shù),則認(rèn)為是一個(gè)響應(yīng)式對(duì)象,就需要進(jìn)行遞歸遍歷。
在Vue中我們還需要能夠在回調(diào)函數(shù)cb()
中拿到響應(yīng)式數(shù)據(jù)更新前后的新值與舊值。
const data = { foo: 1 } const obj = reactive(data) watch( () => obj.foo, (newValue, oldValue) => { console.log(newValue, oldValue) })
接下來(lái)的問(wèn)題是,如何獲取newValue
與oldValue
。newValue
好解決,執(zhí)行完回調(diào)函數(shù)cb()
得到的就是newValue
,但這里如何獲取oldValue
的值呢?要從watch
中拿到舊值,那就不能讓副作用函數(shù)被立即執(zhí)行。這里想到了什么?對(duì),在實(shí)現(xiàn)計(jì)算屬性的時(shí)候,我們用到過(guò)的lazy
,它可以禁止副作用函數(shù)自動(dòng)執(zhí)行。
function watch(getter, cb) { if(typeof getter !== 'function') getter = traverse(getter) let oldValue const effectFn = effect( () => getter(), { lazy: true, // (3) scheduler() { cb(oldValue) } } ) oldValue = effectFn() // (4) }
在(3)處我們?cè)O(shè)置了lazy
開(kāi)關(guān),設(shè)置了lazy
后,副作用函數(shù)的執(zhí)行權(quán)就交到了我們自己手上。在(4)處,我們手動(dòng)執(zhí)行了副作用函數(shù)。這里可以需要我們向前回顧一下,前面我們傳入的getter
是一個(gè)函數(shù)() => obj.foo
,而effect
函數(shù)的第一個(gè)參數(shù)就是真正被執(zhí)行的副作用函數(shù),所以我們手動(dòng)執(zhí)行的,其實(shí)就是函數(shù)() => obj.foo
,這樣我們就拿到了舊值。
如何獲取新值呢?在響應(yīng)式數(shù)據(jù)的值更新后,副作用函數(shù)effect
會(huì)被觸發(fā)執(zhí)行,當(dāng)調(diào)度器屬性存在時(shí),執(zhí)行調(diào)度器。在調(diào)度器中,我們可以再次執(zhí)行副作用函數(shù),通過(guò)() => obj.foo
拿到改變后的新值。
function watch(getter, cb) { if(typeof getter !== 'function') getter = traverse(getter) let oldValue, newValue const effectFn = effect( () => getter(), { lazy: true, scheduler() { newValue = effectFn() cb(newValue, oldValue) oldValue = newValue // (5) } } ) oldValue = effectFn() }
在(5)處,執(zhí)行完回調(diào)函數(shù)cb()
,我們進(jìn)行了一下善后工作,更新了oldValue
的值,為下一次回調(diào)做準(zhǔn)備。
有時(shí),我們還希望偵聽(tīng)器可以在創(chuàng)建時(shí)就立即執(zhí)行回調(diào)函數(shù)。
const data = { foo: 1 } const obj = reactive(data) watch( () => obj.foo, (newValue, oldValue) => { console.log('newValue:', newValue,', oldValue:', oldValue) }, { immediate: true } )
當(dāng)immediate
的值為true
時(shí),需要立即執(zhí)行。明確了需求,我們來(lái)完善watch
偵聽(tīng)器。
function watch(getter, cb, options = {}) { if(typeof getter !== 'function') getter = traverse(getter) let oldValue, newValue function job() { // (6) newValue = effectFn() cb(newValue, oldValue) oldValue = newValue } const effectFn = effect( () => getter(), { lazy: true, scheduler: job, } ) if(options.immediate) { // (7) job() } else { oldValue = effectFn() } }
在(6)處,我們抽離了回調(diào)函數(shù)的執(zhí)行邏輯,當(dāng)options.immediate
存在時(shí),直接觸發(fā)執(zhí)行。
“Vue3偵聽(tīng)器怎么應(yīng)用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
文章題目:Vue3偵聽(tīng)器怎么應(yīng)用
分享路徑:http://bm7419.com/article22/iihgcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、標(biāo)簽優(yōu)化、靜態(tài)網(wǎng)站、網(wǎng)站策劃、移動(dòng)網(wǎng)站建設(shè)、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)