淺談 vue 中的 watcher,淺談vuewatcher

來源:互聯網
上載者:User

淺談 vue 中的 watcher,淺談vuewatcher

觀察 Watchers

雖然計算屬性在大多數情況下更合適,但有時也需要一個自訂的 watcher 。這是為什麼 Vue 提供一個更通用的方法通過watch 選項,來響應資料的變化。當你想要在資料變化響應時,執行非同步作業或開銷較大的操作,這是很有用的。

大家對於 watch 應該不陌生,項目中都用過下面這種寫法:

watch: { someProp () {  // do something }}// 或者watch: { someProp: {  deep: true,  handler () {   // do something  } }}

上面的寫法告訴 vue,我需要監聽 someProp 屬性的變化,於是 vue 在內部就會為我們建立一個 watcher 對象。(限於篇幅,我們不聊 watcher 的具體實現,感興趣的可以直接看源碼 watcher)

然而在 vue 中,watcher 的功能並沒有這麼單一,先上段代碼:

<template> <div>  <p>a: {{ a }}</p>  <p>b: {{ b }}</p>  <button @click="increment">+</button> </div></template><script>export default { data () {  return {   a: 1  } }, computed: {  b () {   return this.a * 2  } }, watch: {  a () {    console.log('a is changed')  } }, methods: {  increment () {   this.a += 1  } }, created () {  console.log(this._watchers) }}</script>

線上demo

上面代碼非常簡單,我們現在主要關注 created 鉤子中列印的 this._watchers,如下:

分別展開三個 watcher,觀察每一個 expression,從上到下分別為:

b() {   return this.a * 2;↵  }"a"function () {   vm._update(vm._render(), hydrating);↵  }

上面三個 watcher 代表了三種不同功能的 watcher,我們將其按功能分為三類:

  • 在 watch 中定義的,用於監聽屬性變化的 watcher (第二個)
  • 用於 computed 屬性的 watcher (第一個)
  • 用於頁面更新的 watcher (第三個)

normal-watcher

我們在 watch 中定義的,都屬於這種類型,即只要監聽的屬性改變了,都會觸發定義好的回呼函數

computed-watcher

每一個 computed 屬性,最後都會產生一個對應的 watcher 對象,但是這類 watcher 有個特點,我們拿上面的 b 舉例:

屬性 b 依賴 a,當 a 改變的時候,b 並不會立即重新計算,只有之後其他地方需要讀取 b 的時候,它才會真正計算,即具備 lazy(懶計算)特性

render-watcher

每一個組件都會有一個 render-watcher, function () {↵ vm._update(vm._render(), hydrating);↵ }, 當 data/computed

中的屬性改變的時候,會調用該 render-watcher 來更新群組件的視圖

三種 watcher 的執行順序

除了功能上的區別,這三種 watcher 也有固定的執行順序,分別是:

computed-render -> normal-watcher -> render-watcher

這樣安排是有原因的,這樣就能儘可能的保證,在更新群組件視圖的時候,computed 屬性已經是最新值了,如果 render-watcher 排在 computed-render 前面,就會導致頁面更新的時候 computed 值為舊資料。

下面從一段執行個體代碼中看下vue中的watcher

在這個樣本中,使用 watch 選項允許我們執行非同步作業(訪問一個 API),限制我們執行該操作的頻率,並在我們得到最終結果前,設定中間狀態。這是計算屬性無法做到的。

<div id="watch-example"><p>Ask a yes/no question:<input v-model="question"></p><p>{{ answer }}</p></div><!-- Since there is already a rich ecosystem of ajax libraries --><!-- and collections of general-purpose utility methods, Vue core --><!-- is able to remain small by not reinventing them. This also --><!-- gives you the freedom to just use what you're familiar with. --><script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script><script src="https://unpkg.com/lodash@4.13.1/lodash.min.js"></script><script>var watchExampleVM = new Vue({el: '#watch-example',data: {question: '',answer: 'I cannot give you an answer until you ask a question!'},watch: { // 如果 question 發生改變,這個函數就會運行question: function (newQuestion) {this.answer = 'Waiting for you to stop typing...'this.getAnswer()}},methods: { // _.debounce 是一個通過 lodash 限制操作頻率的函數。 // 在這個例子中,我們希望限制訪問yesno.wtf/api的頻率 // ajax請求直到使用者輸入完畢才會發出 // 學習

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.