首頁  >  文章  >  web前端  >  vue 中的 watcher詳解

vue 中的 watcher詳解

PHPz
PHPz原創
2018-05-12 16:27:146659瀏覽

雖然計算屬性在大多數情況下更合適,但有時也需要一個自訂的 watcher 。這就是為什麼 Vue 提供一個更通用的方法透過watch 選項,來回應資料的變化。當你想要在資料變化回應時,執行非同步操作或開銷較大的操作,這是很有用的。本文主要介紹了vue 中的 watcher的相關資料,需要的朋友可以參考下,希望能幫助到大家。

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

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

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

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

<template>
 <p>
  <p>a: {{ a }}</p>
  <p>b: {{ b }}</p>
  <button @click="increment">+</button>
 </p>
</template>
<script>
export default {
 data () {
  return {
   a: 1
  }
 },
 computed: {
  b () {
   return this.a * 2
  }
 },
 watch: {
  a () {
    console.log(&#39;a is changed&#39;)
  }
 },
 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),限制我們執行該操作的頻率,並在我們得到最終結果之前,設定中間狀態。這是計算屬性無法做到的。

<p id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</p>
<!-- 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&#39;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: &#39;#watch-example&#39;,
data: {
question: &#39;&#39;,
answer: &#39;I cannot give you an answer until you ask a question!&#39;
},
watch: {
 // 如果 question 发生改变,这个函数就会运行
question: function (newQuestion) {
this.answer = &#39;Waiting for you to stop typing...&#39;
this.getAnswer()
}
},
methods: {
 // _.debounce 是一个通过 lodash 限制操作频率的函数。
 // 在这个例子中,我们希望限制访问yesno.wtf/api的频率
 // ajax请求直到用户输入完毕才会发出
 // 学习更多关于 _.debounce function (and its cousin
// _.throttle), 参考: https://lodash.com/docs#debounce
getAnswer: _.debounce(
function () {
var vm = this
if (this.question.indexOf(&#39;?&#39;) === -1) {
vm.answer = &#39;Questions usually contain a question mark. ;-)&#39;
return
}
vm.answer = &#39;Thinking...&#39;
axios.get(&#39;https://yesno.wtf/api&#39;)
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = &#39;Error! Could not reach the API. &#39; + error
})
},
// 这是我们为用户停止输入等待的毫秒数
500
)
}
})
</script>

相關推薦:

Vue 方法與事件處理的問題

Vue 2.0中內部指令是什麼

#前端的VUE怎麼使用

以上是vue 中的 watcher詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn