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

Vue3偵聽器的實現(xiàn)原理詳情

 更新時間:2022年08月30日 11:54:05   作者:???????咕咕雞_  
這篇文章主要介紹了Vue3偵聽器的實現(xiàn)原理詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

前言:

本篇內(nèi)容基于Vue3計算屬性是如何實現(xiàn)的實現(xiàn)。

偵聽響應(yīng)式對象

前面我們聊到計算屬性,它可以自動計算并緩存響應(yīng)式數(shù)據(jù)的值。而如果我們僅需要在響應(yīng)式數(shù)據(jù)變化時,執(zhí)行一些預(yù)設(shè)的操作,就可以使用watch偵聽器。我們還是先來實現(xiàn)一個最簡單的例子,然后來一點一點擴充它。

const data = {foo: 1}
const obj = reactive(data)
watch(obj, () => {
  console.log('obj已改變')
})

在這個例子中,我們使用了watch偵聽器,當(dāng)obj的屬性被改變時,控制臺應(yīng)該會打印出obj已改變。基于前面我們對計算屬性的實現(xiàn),這里我們已經(jīng)有了一個大概的思路。把watch視為響應(yīng)式對象的副作用函數(shù),當(dāng)響應(yīng)式對象改變時,觸發(fā)執(zhí)行該副作用函數(shù)。

想要觸發(fā)副作用函數(shù),必須先收集它,還記得副作用函數(shù)是如何收集的嗎?對,當(dāng)響應(yīng)式數(shù)據(jù)被get時,收集副作用函數(shù)。所以首先,我們需要讓watch被響應(yīng)式對象收集到。     

function watch(getter, cb) {
  effect(
    () => getter.foo
  )
}

接著,我們還需要讓我們預(yù)設(shè)的方法被執(zhí)行。當(dāng)響應(yīng)式數(shù)據(jù)被set時,觸發(fā)副作用函數(shù)。這里我們想觸發(fā)的是cb這個傳入的回調(diào)函數(shù),這里我們就又能用到實現(xiàn)計算屬性時的調(diào)度器了,當(dāng)調(diào)度器存在時,set觸發(fā)的trigger會先執(zhí)行調(diào)度器中的函數(shù)。

function watch(getter, cb) {
  effect(
    () => getter.foo,
    {
      scheduler() {
        cb()
      }
    }
  )
}

一個簡單的偵聽器已經(jīng)完成了!這里我們?yōu)榱撕唵?,把功能寫死了,僅支持對obj.foo的偵聽。接下來,我們就要想想,如何實現(xiàn)對響應(yīng)式對象的任意屬性進行偵聽?

按照前面的思路,想要實現(xiàn)對響應(yīng)式對象的任意屬性的偵聽,就需要我們get到該對象的每一個屬性,這就需要我們對響應(yīng)式對象進行一次遞歸遍歷。

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
}

為了避免遞歸遍歷對象時,循環(huán)引用造成的死循環(huán),我們在(1)處創(chuàng)建了Set,當(dāng)重復(fù)出現(xiàn)相同的對象時,直接返回。

偵聽屬性值

在Vue3中,我們不能直接偵聽響應(yīng)式對象的屬性值。如果需要偵聽響應(yīng)式對象的屬性值,就需要一個getter函數(shù),讓偵聽器能被響應(yīng)式對象收集到。

const data = {
  foo: 1
}
const obj = reactive(data)
watch(
  () => obj.foo, 
  () => {
  console.log('obj.foo已改變')
})

指定了屬性就意味著,當(dāng)前的偵聽器僅會被指定的屬性觸發(fā),就無需遞歸遍歷整個響應(yīng)式對象了。

function watch(getter, cb) {
  if(typeof getter !== 'function') getter = traverse(getter) // (2)
  effect(
    () => getter(),
    {
      scheduler() {
        cb()
      }
    }
  )
}

在(2)處,我們增加了一個判斷,如果傳入的已經(jīng)是getter函數(shù),我們直接使用,如果不是getter函數(shù),則認(rèn)為是一個響應(yīng)式對象,就需要進行遞歸遍歷。

偵聽獲取新值和舊值

在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)
})

接下來的問題是,如何獲取newValueoldValuenewValue好解決,執(zhí)行完回調(diào)函數(shù)cb()得到的就是newValue,但這里如何獲取oldValue的值呢?要從watch中拿到舊值,那就不能讓副作用函數(shù)被立即執(zhí)行。這里想到了什么?對,在實現(xiàn)計算屬性的時候,我們用到過的lazy,它可以禁止副作用函數(shù)自動執(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)處我們設(shè)置了lazy開關(guān),設(shè)置了lazy后,副作用函數(shù)的執(zhí)行權(quán)就交到了我們自己手上。在(4)處,我們手動執(zhí)行了副作用函數(shù)。這里可以需要我們向前回顧一下,前面我們傳入的getter是一個函數(shù)() => obj.foo,而effect函數(shù)的第一個參數(shù)就是真正被執(zhí)行的副作用函數(shù),所以我們手動執(zhí)行的,其實就是函數(shù)() => obj.foo,這樣我們就拿到了舊值。

如何獲取新值呢?在響應(yīng)式數(shù)據(jù)的值更新后,副作用函數(shù)effect會被觸發(fā)執(zhí)行,當(dāng)調(diào)度器屬性存在時,執(zhí)行調(diào)度器。在調(diào)度器中,我們可以再次執(zhí)行副作用函數(shù),通過() => 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(),我們進行了一下善后工作,更新了oldValue的值,為下一次回調(diào)做準(zhǔn)備。

有時,我們還希望偵聽器可以在創(chuàng)建時就立即執(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時,需要立即執(zhí)行。明確了需求,我們來完善watch偵聽器。

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存在時,直接觸發(fā)執(zhí)行。

實現(xiàn)效果

到此這篇關(guān)于Vue3偵聽器是如何實現(xiàn)的的文章就介紹到這了,更多相關(guān)Vue3偵聽器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 學(xué)習(xí) Vue.js 遇到的那些坑

    學(xué)習(xí) Vue.js 遇到的那些坑

    這篇文章主要介紹了學(xué)習(xí) Vue.js 遇到的那些坑,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下
    2021-02-02
  • vuex中數(shù)據(jù)持久化插件vuex-persistedstate使用詳解

    vuex中數(shù)據(jù)持久化插件vuex-persistedstate使用詳解

    這篇文章主要介紹了vuex中數(shù)據(jù)持久化插件vuex-persistedstate使用詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • vue實現(xiàn)提示保存后退出的方法

    vue實現(xiàn)提示保存后退出的方法

    下面小編就為大家分享一篇vue實現(xiàn)提示保存后退出的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • vue實現(xiàn)購物車小案例

    vue實現(xiàn)購物車小案例

    這篇文章主要為大家詳細(xì)介紹了vue實現(xiàn)購物車小案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • mpvue 項目初始化及實現(xiàn)授權(quán)登錄的實現(xiàn)方法

    mpvue 項目初始化及實現(xiàn)授權(quán)登錄的實現(xiàn)方法

    這篇文章主要介紹了mpvue 項目初始化及實現(xiàn)授權(quán)登錄的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • vue實現(xiàn)點擊展開點擊收起效果

    vue實現(xiàn)點擊展開點擊收起效果

    這篇文章主要介紹了vue實現(xiàn)點擊展開,點擊收起效果,首先我們需要定義data里面的數(shù)據(jù),使用computed對data進行處理,需要的朋友可以參考下
    2018-04-04
  • 在Nginx上部署前端Vue項目的詳細(xì)步驟(超級簡單!)

    在Nginx上部署前端Vue項目的詳細(xì)步驟(超級簡單!)

    這篇文章主要介紹了在Nginx上部署前端Vue項目的詳細(xì)步驟,Nginx是一款高效的HTTP和反向代理Web服務(wù)器,作為開源軟件,Nginx以其高性能、可擴展性和靈活性廣泛應(yīng)用于Web架構(gòu)中,文中將步驟介紹的非常詳細(xì),需要的朋友可以參考下
    2024-10-10
  • vue如何使用模擬的json數(shù)據(jù)查看效果

    vue如何使用模擬的json數(shù)據(jù)查看效果

    這篇文章主要介紹了vue如何使用模擬的json數(shù)據(jù)查看效果,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 實例詳解vue中的$root和$parent

    實例詳解vue中的$root和$parent

    這篇文章主要介紹了vue中的$root和$parent ,本文通過文字實例代碼相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-04-04
  • Vue組件解析之如何自定義彈窗組件ByDialog

    Vue組件解析之如何自定義彈窗組件ByDialog

    這篇文章主要介紹了Vue組件解析之如何自定義彈窗組件ByDialog問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評論

阿坝| 怀远县| 芷江| 汤原县| 沙坪坝区| 珠海市| 海原县| 大连市| 清水河县| 夏邑县| 册亨县| 页游| 祁门县| 郴州市| 郧西县| 青海省| 德州市| 乌拉特中旗| 佳木斯市| 新闻| 阳高县| 巴东县| 建湖县| 宁城县| 靖宇县| 凌云县| 永新县| 腾冲县| 江门市| 古浪县| 偃师市| 东乌珠穆沁旗| 陵川县| 清流县| 石首市| 通渭县| 宁晋县| 广安市| 萝北县| 应城市| 曲周县|