中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue3偵聽器的實現原理是什么

發布時間:2022-08-30 14:08:54 來源:億速云 閱讀:162 作者:iii 欄目:開發技術

這篇文章主要講解了“Vue3偵聽器的實現原理是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Vue3偵聽器的實現原理是什么”吧!

偵聽響應式對象

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

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

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

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

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

接著,我們還需要讓我們預設的方法被執行。當響應式數據被set時,觸發副作用函數。這里我們想觸發的是cb這個傳入的回調函數,這里我們就又能用到實現計算屬性時的調度器了,當調度器存在時,set觸發的trigger會先執行調度器中的函數。

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

Vue3偵聽器的實現原理是什么

一個簡單的偵聽器已經完成了!這里我們為了簡單,把功能寫死了,僅支持對obj.foo的偵聽。接下來,我們就要想想,如何實現對響應式對象的任意屬性進行偵聽?

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

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
}

為了避免遞歸遍歷對象時,循環引用造成的死循環,我們在(1)處創建了Set,當重復出現相同的對象時,直接返回。

偵聽屬性值

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

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

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

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

Vue3偵聽器的實現原理是什么

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

偵聽獲取新值和舊值

在Vue中我們還需要能夠在回調函數cb()中拿到響應式數據更新前后的新值與舊值。

const data = {
  foo: 1
}
const obj = reactive(data)
watch(
  () => obj.foo, 
  (newValue, oldValue) => {
  console.log(newValue, oldValue)
})

接下來的問題是,如何獲取newValueoldValuenewValue好解決,執行完回調函數cb()得到的就是newValue,但這里如何獲取oldValue的值呢?要從watch中拿到舊值,那就不能讓副作用函數被立即執行。這里想到了什么?對,在實現計算屬性的時候,我們用到過的lazy,它可以禁止副作用函數自動執行。

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)處我們設置了lazy開關,設置了lazy后,副作用函數的執行權就交到了我們自己手上。在(4)處,我們手動執行了副作用函數。這里可以需要我們向前回顧一下,前面我們傳入的getter是一個函數() => obj.foo,而effect函數的第一個參數就是真正被執行的副作用函數,所以我們手動執行的,其實就是函數() => obj.foo,這樣我們就拿到了舊值。

如何獲取新值呢?在響應式數據的值更新后,副作用函數effect會被觸發執行,當調度器屬性存在時,執行調度器。在調度器中,我們可以再次執行副作用函數,通過() => 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)處,執行完回調函數cb(),我們進行了一下善后工作,更新了oldValue的值,為下一次回調做準備。

Vue3偵聽器的實現原理是什么

有時,我們還希望偵聽器可以在創建時就立即執行回調函數。

const data = {
  foo: 1
}
const obj = reactive(data)
watch(
  () => obj.foo, 
  (newValue, oldValue) => {
      console.log('newValue:', newValue,', oldValue:', oldValue)
  },
  { immediate: true }
)

immediate的值為true時,需要立即執行。明確了需求,我們來完善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)處,我們抽離了回調函數的執行邏輯,當options.immediate存在時,直接觸發執行。

Vue3偵聽器的實現原理是什么

實現效果

Vue3偵聽器的實現原理是什么

感謝各位的閱讀,以上就是“Vue3偵聽器的實現原理是什么”的內容了,經過本文的學習后,相信大家對Vue3偵聽器的實現原理是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

逊克县| 普兰县| 冷水江市| 长子县| 永仁县| 灵寿县| 南陵县| 上栗县| 本溪市| 游戏| 巴楚县| 苍溪县| 福建省| 台南县| 新宁县| 铁岭县| 博白县| 吉木乃县| 财经| 潍坊市| 昆明市| 东宁县| 南木林县| 新建县| 宜州市| 隆德县| 隆尧县| 武乡县| 兰西县| 江门市| 临澧县| 华容县| 祁门县| 鄂托克旗| 长兴县| 长汀县| 潞城市| 乌兰县| 即墨市| 泊头市| 志丹县|