Rumah  >  Artikel  >  hujung hadapan web  >  Apakah prinsip responsif Vue?

Apakah prinsip responsif Vue?

醉折花枝作酒筹
醉折花枝作酒筹ke hadapan
2021-07-29 17:42:193003semak imbas

Saya telah membaca banyak artikel mengenai prinsip Vue baru-baru ini Dengan bantuan artikel ini, saya telah mencuba berkali-kali untuk memahami kod sumber Vue sendiri. Akhir sekali, saya fikir sudah tiba masanya untuk mengeluarkan kandungan itu sendiri. Saya harap saya dapat membiasakan semua orang dengan Vue dari perspektif yang berbeza daripada artikel lain.

Apakah prinsip responsif Vue?

Dep

var Dep = function Dep() {
  this.id = uid++
  this.subs = []
}

Maksud Dep secara semula jadi adalah kebergantungan (iaitu pergantungan, kata nama dalam medan komputer).

Sama seperti menulis program node.js, kebergantungan daripada gudang npm sering digunakan. Dalam Vue, kebergantungan secara khusus merujuk kepada data yang diproses secara reaktif. Seperti yang akan dinyatakan kemudian, salah satu fungsi utama pemprosesan reaktif ialah defineReactive, yang disebut dalam banyak artikel prinsip Vue. Selepas

Dep terikat pada setiap data responsif, data responsif akan menjadi kebergantungan (kata nama) Apabila memperkenalkan Pemerhati di bawah, ia akan disebut bahawa data responsif boleh ditonton, dikira atau dalam Penggunaan templat 3 kes pergantungan (kata kerja).

subs

Terdapat atribut subs di bawah objek Dep, iaitu tatasusunan Mudah untuk meneka bahawa ia bermaksud senarai pelanggan. Pelanggan mungkin fungsi jam tangan, fungsi dikira, atau lihat fungsi kemas kini.

Watcher

Watcher ialah subscriber yang disebut dalam Dep (jangan dikelirukan dengan Observer observer nanti).

Oleh kerana fungsi Watcher adalah untuk membalas kemas kini Dep tepat pada masanya, sama seperti push langganan sesetengah apl Jika anda (Watcher) melanggan maklumat tertentu (Dep), anda akan diingatkan untuk membaca apabila maklumat dikemas kini.

deps

Sama seperti Dep yang mempunyai atribut subs, objek Watcher juga mempunyai atribut deps. Ini membentuk hubungan banyak-ke-banyak antara Watcher dan Dep Sebab untuk merekodkan satu sama lain ialah apabila satu pihak dibersihkan, objek berkaitan boleh dikemas kini dalam masa.

Cara menjana Watcher

Templat jam tangan, pengiraan dan pemaparan yang disebut berkali-kali di atas menjana Watcher, yang semuanya ringkas dan mudah difahami dalam kod sumber Vue :

  • mountComponent's vm._watcher = new Watcher(vm, updateComponent, noop);
  • initComputed's watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions )
  • $watcher's var watcher = new Watcher(vm, expOrFn, cb, options);

Pemerhati

Pemerhati ialah pemerhati, dia bertanggungjawab secara rekursif memerhati (atau memproses) objek reaktif (atau tatasusunan). Dalam contoh yang dicetak, anda boleh melihat bahawa objek reaktif akan mempunyai __ob__, yang merupakan bukti apa yang telah diperhatikan. Pemerhati tidaklah sepenting Dep dan Watcher di atas, sekadar memahami sedikit sahaja sudah memadai.

berjalan

Observer.prototype.walk ialah kaedah teras pemprosesan rekursif semasa pemulaan Observer, tetapi kaedah ini digunakan untuk memproses objek, dan terdapat juga Observer. tatasusunan Proses prototaip.observeArray.

Proses Teras

Mengikut hubungan antara konsep di atas, bagaimana untuk memadankannya dan bagaimana untuk mencapai kemas kini data responsif?

Pertama sekali, kami menetapkan matlamat kami: secara semulajadi, apabila data dikemas kini, paparan akan dimuat semula secara automatik untuk memaparkan data terkini.

Ini ialah hubungan antara Dep dan Watcher yang dinyatakan di atas Datanya ialah Dep, dan Watcher mencetuskan fungsi pemaparan halaman (ini adalah pemerhati yang paling penting).

Tetapi timbul persoalan baru, bagaimana Dep tahu bahawa mana-mana Watchers bergantung kepadanya?

Vue menggunakan kaedah yang sangat menarik:

  • Sebelum menjalankan fungsi panggil balik Watcher, tulis dahulu apakah Watcher semasa (melalui Dep.target)

  • Jika data responsif digunakan dalam fungsi panggil balik yang sedang berjalan, maka fungsi getter data responsif pasti akan dipanggil

  • Dalam fungsi getter responsif data Anda boleh merekodkan Watcher semasa dan mewujudkan hubungan antara Dep dan Watcher

  • Selepas itu, apabila data responsif dikemas kini, fungsi setter bagi data responsif pasti akan dipanggil

  • Berdasarkan perhubungan yang telah diwujudkan sebelum ini, fungsi panggil balik yang sepadan dengan Watcher boleh dicetuskan dalam fungsi setter

Kod

Logik di atas adalah di tengah fungsi defineReactive. Terdapat banyak pintu masuk ke fungsi ini Mari kita bercakap tentang fungsi pemerhatian yang lebih penting dahulu.

Dalam fungsi observe, objek Observer baharu dicipta, di mana Observer.prototype.walk digunakan untuk memproses nilai dalam objek satu demi satu secara responsif, dan fungsi defineReactive digunakan .

Oleh kerana fungsi defineReactive sangat penting dan tidak panjang, adalah lebih mudah untuk menyiarkannya di sini secara terus.

function defineReactive(obj, key, val, customSetter, shallow) {
  var dep = new Dep()
  depsArray.push({ dep, obj, key })
  var property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  var getter = property && property.get
  var setter = property && property.set

  var childOb = !shallow && observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      var value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter(newVal) {
      var value = getter ? getter.call(obj) : val
      // 后半部分诡异的条件是用于判断新旧值都是 NaN 的情况
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      // customSetter 用于提醒你设置的值可能存在问题
      if ('development' !== 'production' && customSetter) {
        customSetter()
      }
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify()
    },
  })
}

Pertama sekali, setiap nilai responsif ialah "pergantungan", jadi pada langkah pertama, kami menggunakan keupayaan penutupan untuk mencipta Dep bagi setiap nilai. (Dengan Vue 3, tidak ada keperluan untuk penutupan)

Kemudian lihat pada tiga parameter teras:

  • obj Objek di mana nilai pada masa ini perlu diproses secara responsif

  • kunci nilai kunci

  • nilai semasa val

Nilai ini mungkin telah ditakrifkan sebelum milik getter dan setter, jadi apabila melakukan pemprosesan responsif Vue, getter dan setter asal diproses terlebih dahulu.

Seperti yang dinyatakan di atas dalam proses teras, fungsi getter akan mewujudkan hubungan antara Dep dan Watcher, khususnya bergantung pada dep.depend().

Disiarkan di bawah adalah beberapa kaedah untuk Dep dan Watcher menghubungi satu sama lain:

Dep.prototype.depend = function depend() {
  if (Dep.target) {
    Dep.target.addDep(this)
  }
}
Watcher.prototype.addDep = function addDep(dep) {
  var id = dep.id
  if (!this.newDepIds.has(id)) {
    this.newDepIds.add(id)
    this.newDeps.push(dep)
    if (!this.depIds.has(id)) {
      dep.addSub(this)
    }
  }
}
Dep.prototype.addSub = function addSub(sub) {
  this.subs.push(sub)
}

通过这几个函数,可以领略到了 Dep 和 Watcher 错综复杂的关系……不过看起来迂回,简单来说,其实做的就是上面说的互相添加到多对多列表。

你可以在 Dep 的 subs 找到所有订阅同一个 Dep 的 Watcher,也可以在 Watcher 的 deps 找到所有该 Watcher 订阅的所有 Dep。

但是里面还有一个隐藏问题,就是 Dep.target 怎么来呢?先放一放,后会作出解答。先接着看看 setter 函数,其中的关键是 dep.notify()。

Dep.prototype.notify = function notify() {
  // stabilize the subscriber list first
  var subs = this.subs.slice()
  for (var i = 0, l = subs.length; i < l; i++) {
    subs[i].update()
  }
}

不难理解,就是 Dep 提醒他的订阅者列表(subs)里的所有人更新,所谓订阅者都是 Watcher,subs[i].update() 调用的也就是 Watcher.prototype.update。

那么来看一下 Watcher 的 update 做了什么——

Watcher.prototype.update = function update() {
  if (this.lazy) {
    this.dirty = true
  } else if (this.sync) {
    this.run()
  } else {
    queueWatcher(this)
  }
}

在这里我觉得有两个点比较值得展开,所以挖点坑

Atas ialah kandungan terperinci Apakah prinsip responsif Vue?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

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