Rumah  >  Artikel  >  hujung hadapan web  >  Apakah prinsip pelaksanaan pendengar Vue3

Apakah prinsip pelaksanaan pendengar Vue3

王林
王林ke hadapan
2023-05-16 15:04:061385semak imbas

Mendengar objek responsif

Terdahulu kita bercakap tentang sifat yang dikira, yang secara automatik boleh mengira dan cache nilai data responsif. Dan jika kita hanya perlu melakukan beberapa operasi pratetap apabila data responsif berubah, kita boleh menggunakan pendengar watch. Mari kita laksanakan contoh paling mudah dahulu, dan kemudian kembangkannya sedikit demi sedikit.

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

Dalam contoh ini, kami menggunakan watch pendengar, dan apabila sifat obj ditukar, konsol harus mencetak obj已改变. Berdasarkan pelaksanaan hartanah terkira kami sebelum ini, kami sudah mempunyai idea umum di sini. Fikirkan watch sebagai fungsi kesan sampingan objek responsif Apabila objek responsif berubah, pelaksanaan fungsi kesan sampingan dicetuskan.

Jika anda ingin mencetuskan fungsi kesan sampingan, anda mesti mengumpulnya dahulu Adakah anda masih ingat bagaimana fungsi kesan sampingan dikumpul? Ya, mengumpul fungsi kesan sampingan get apabila data reaktif diluluskan. Jadi pertama, kita perlu membuat watch dikumpul oleh objek reaktif.

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

Seterusnya, kami juga perlu membiarkan kaedah lalai kami dilaksanakan. Apabila data reaktif adalah set, fungsi kesan sampingan dicetuskan. Apa yang ingin kita cetuskan di sini ialah fungsi panggil balik yang dihantar dalam cb Di sini kita boleh menggunakan penjadual apabila melaksanakan sifat yang dikira Apabila penjadual wujud, set yang dicetuskan oleh trigger akan melaksanakan fungsi itu terlebih dahulu pemproses.

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

Apakah prinsip pelaksanaan pendengar Vue3

Pendengar mudah sudah lengkap! Di sini, demi kesederhanaan, kami telah menulis fungsi itu hingga mati dan hanya menyokong mendengar untuk obj.foo. Seterusnya, kita perlu memikirkan bagaimana untuk mendengar mana-mana sifat objek responsif?

Mengikut idea sebelumnya, jika kita ingin mendengar sebarang atribut objek responsif, kita perlu get mengakses setiap atribut objek, yang memerlukan kita melakukan rekursi pada objek responsif. merentasi.

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
}

Untuk mengelakkan gelung tak terhingga yang disebabkan oleh rujukan bulat apabila melintasi objek secara rekursif, kami mencipta (1) pada Set dan kembali terus apabila objek yang sama muncul berulang kali.

Mendengar nilai harta

Dalam Vue3, kita tidak boleh mendengar secara langsung nilai sifat objek reaktif. Jika anda perlu mendengar nilai sifat objek reaktif, anda memerlukan fungsi getter supaya pendengar boleh dikumpulkan oleh objek reaktif.

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

Menentukan atribut bermakna pendengar semasa hanya akan dicetuskan oleh atribut yang ditentukan dan tidak perlu melintasi keseluruhan objek responsif secara rekursif.

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

Apakah prinsip pelaksanaan pendengar Vue3

Pada (2), kami menambah penghakiman Jika yang diluluskan sudah menjadi fungsi getter, kami menggunakannya secara langsung Jika ia bukan getter fungsi, Jika ia dianggap sebagai objek responsif, ia perlu dilalui secara rekursif.

Dengar untuk mendapatkan nilai baharu dan lama

Dalam Vue kita juga perlu mendapat nilai baharu dan lama sebelum dan selepas kemas kini data responsif dalam fungsi panggil balik cb().

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

Soalan seterusnya ialah, bagaimana untuk mendapatkan newValue dan oldValue. newValue mudah diselesaikan Selepas melaksanakan fungsi panggil balik cb(), anda akan mendapat newValue, tetapi bagaimana untuk mendapatkan nilai oldValue di sini? Untuk mendapatkan nilai lama daripada watch, fungsi kesan sampingan tidak boleh dilaksanakan serta-merta. Apa yang terlintas di fikiran di sini? Ya, apabila melaksanakan sifat yang dikira, kami telah menggunakan lazy, yang boleh melarang pelaksanaan automatik fungsi kesan sampingan.

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

Pada (3) kami menetapkan suis lazy Selepas menetapkan lazy, hak pelaksanaan fungsi kesan sampingan diserahkan kepada diri kami sendiri. Pada (4), kami melaksanakan fungsi kesan sampingan secara manual. Kita perlu melihat kembali di sini. getter yang kita lalui tadi ialah fungsi () => obj.foo, dan parameter pertama fungsi effect ialah fungsi kesan sampingan yang sebenarnya dilaksanakan, jadi apa yang kita laksanakan secara manual sebenarnya adalah Fungsi. () => obj.foo, jadi kita dapat nilai lama.

Bagaimana untuk mendapatkan nilai baharu? Selepas nilai data responsif dikemas kini, fungsi kesan sampingan effect akan dicetuskan untuk dilaksanakan Apabila atribut penjadual wujud, penjadual akan dilaksanakan. Dalam penjadual, kita boleh melaksanakan fungsi kesan sampingan sekali lagi dan mendapatkan nilai tukar baharu melalui () => 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()
}

Pada (5), selepas melaksanakan fungsi panggil balik cb(), kami melakukan beberapa kerja selepas itu dan mengemas kini nilai oldValue untuk menyediakan panggilan balik seterusnya.

Apakah prinsip pelaksanaan pendengar Vue3

Kadangkala, kami juga mahu pendengar melaksanakan fungsi panggil balik serta-merta apabila ia dicipta.

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

Apabila nilai immediate ialah true, ia perlu dilaksanakan segera. Selepas menjelaskan keperluan, mari kita perbaiki watch pendengar.

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存在时,直接触发执行。

Apakah prinsip pelaksanaan pendengar Vue3

实现效果

Apakah prinsip pelaksanaan pendengar Vue3

Atas ialah kandungan terperinci Apakah prinsip pelaksanaan pendengar Vue3. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam