vue項目中的數(shù)據(jù)變化被watch監(jiān)聽并處理
vue數(shù)據(jù)變化被watch監(jiān)聽處理
監(jiān)聽當(dāng)前vue文件數(shù)據(jù)
例如,當(dāng)前的vue文件的data中有如下屬性:
data() { ?? ?return { ?? ? ? ?dialogFormVisible: false, ?? ?} }
要監(jiān)聽dialogFormVisible變量的數(shù)據(jù)變化,則代碼如下:
watch: { ? ? dialogFormVisible: function(newVal, oldVal) { ? ? ? alert(newVal); ? ? ? alert(oldVal); ? ? } }
監(jiān)聽vuex中的數(shù)據(jù)
如果vuex中聲明的數(shù)據(jù)如下:
export default new Vuex.Store({ ? state: { ? ? avatar: "",? ? }, ? mutations: {}, ? actions: {}, ? modules: {} });
則監(jiān)聽的代碼如下:
watch: { ? ? "$store.state.avatar": function(newValue, oldValue) { ? ? ? ... ? ? } ? },
如何正確使用watch監(jiān)聽屬性變化
Vue中可以使用監(jiān)聽器監(jiān)聽屬性的變化,并根據(jù)屬性變化作出響應(yīng)。但一旦涉及到復(fù)雜數(shù)據(jù)的監(jiān)聽(如Object,但數(shù)組一般不需要,因為Vue針對數(shù)組做了特殊處理)時就比較復(fù)雜了,本文解釋了使用watch監(jiān)聽屬性變化的方法,包括復(fù)雜數(shù)據(jù)。
基本用法
Vue watch最重要的使用場景是根據(jù)某屬性的變化執(zhí)行某些業(yè)務(wù)邏輯:
<template> ? <input type="number" v-model.number="counter" /> </template>
<script> export default { ? name: "Counter", ? data: function() { ? ? return { ? ? ? counter: 0, ? ? }; ? }, ? watch: { ? ? counter: function(newV, oldV) { ? ? ? console.log('counter change to %d from %d', newV, oldV); ? ? }, ? } }; </script>
watch的基本用法很簡單:針對需要監(jiān)聽的屬性定義個同名的函數(shù)即可,函數(shù)的第一個參數(shù)為變化后的值,第二個參數(shù)為變化前的值。
監(jiān)聽object
首先我們回顧一個JavaScript中的概念:復(fù)雜數(shù)據(jù)變量。“復(fù)雜”的原因在于變量只是一個引用,和C++中的指針類似,其保存的不是真實的數(shù)據(jù),而是數(shù)據(jù)的地址。比如對于一個object變量來說,添加屬性、刪除屬性、修改屬性的值都不會改變這個地址,這也可以說這個object變量沒有變化。不管所用的框架如何,基本定理肯定是生效的,所以Vue中監(jiān)聽object也是一難題,特別是嵌套數(shù)據(jù)的監(jiān)聽。
這里的變化指的是地址的變化,能夠觸發(fā)變化最簡單的方式就是重新賦值。
<template> ? <div> ? ? <label>up trigger {{ counter.up }} times</label> ? ? <button @click="onTrigger('up')">Trigger Up</button> ? ? <br> ? ? <label>down trigger {{ counter.down }} times</label> ? ? <button @click="onTrigger('down')">Trigger down</button> ? </div> </template>
<script> export default { ? name: "Counter", ? data: function() { ? ? return { ? ? ? counter: { ? ? ? ? up: 0, ? ? ? ? down: 0, ? ? ? }, ? ? }; ? }, ? methods: { ? ? onTrigger: function(type) { ? ? ? this.counter[type] += 1; ? ? } ? }, ? watch: { ? ? counter: function(newV, oldV) { ? ? ? // 不會被觸發(fā) ? ? ? console.log('counter change to %o from %o', newV, oldV); ? ? }, ? } }; </script>
針對counter的監(jiān)聽不會被觸發(fā),因為this.counter[type] += 1;并不會使this.counter變化(地址沒變)。那如果想要監(jiān)聽到這個變化應(yīng)該怎么辦呢?一般來說有兩種方式:
使用deep參數(shù)
watch: { ? counter: { ? ? handler: function(newV, oldV) { ? ? ? console.log('counter change to %o from %o', newV, oldV); ? ? }, ? ? deep: true, ? } }
使用deep需要使用watch的完整形式:handler是監(jiān)聽回調(diào)函數(shù),deep: true指定了不僅僅監(jiān)聽counter的變化,也監(jiān)聽其內(nèi)部屬性的變化,所以當(dāng)counter.up或counter.down變化時才能出發(fā)handler回調(diào)。
重新賦值
methods: { ? onTrigger: function(type) { ? ? // 重新賦值觸發(fā)變化 ? ? this.counter = { ? ? ? ...this.counter, ? ? ? [type]: this.counter[type] + 1, ? ? }; ? } }, watch: { ? counter: function(newV, oldV) { ? ? // 不會被觸發(fā) ? ? console.log('counter change to %o from %o', newV, oldV); ? }, }
那兩種方式優(yōu)劣如何呢?使用deep參數(shù)會為數(shù)據(jù)每一層都添加監(jiān)聽,當(dāng)層級較深時比較耗費(fèi)性能,而且Vue不能監(jiān)聽到屬性的添加或刪除。所以一般來說使用重新賦值的方式是較優(yōu)的方案,但如果只是想監(jiān)聽內(nèi)部嵌套數(shù)據(jù)的話,重新賦值就比較重了,所以Vue也提供了直接監(jiān)聽嵌套屬性變化的途徑:
通過路徑監(jiān)聽內(nèi)部數(shù)據(jù)
watch: { ? 'counter.up': function(newV, oldV) { ? ? console.log('counter.up change to %d from %d', newV, oldV); ? }, ? 'counter.down': function(newV, oldV) { ? ? console.log('counter.down change to %d from %d', newV, oldV); ? }, }
通過這種方式可以避免使用deep造成的性能消耗問題,當(dāng)只對某內(nèi)部屬性變化作出響應(yīng)的場景下比較合適,但仍要注意監(jiān)聽的路徑數(shù)據(jù)仍是復(fù)雜數(shù)據(jù)時的場景。
初始化變量觸發(fā)監(jiān)聽回調(diào)
使用watch監(jiān)聽變化時,給變量初始值不會觸發(fā)監(jiān)聽函數(shù),如果像要改變這個默認(rèn)設(shè)定可以使用immediate參數(shù),其用法和deep類似:
watch: { ? counter: { ? ? handler: function(newV, oldV) { ? ? ? console.log('counter change to %o from %o', newV, oldV); ? ? }, ? ? immediate: true, ? } }
這樣在賦初值時就會觸發(fā)監(jiān)聽函數(shù),其中第一個參數(shù)為初始值,第二個參數(shù)為undefined。
總結(jié):使用watch可以監(jiān)聽屬性的變化,且其使用方式也不少,理解每種方式的使用場景能為開發(fā)節(jié)省時間,優(yōu)化性能。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue中實現(xiàn)父子組件雙向數(shù)據(jù)流的三種方案分享
通常情況下,父子組件的通信都是單向的,或父組件使用props向子組件傳遞數(shù)據(jù),或子組件使用emit函數(shù)向父組件傳遞數(shù)據(jù),本文將嘗試講解Vue中常用的幾種雙向數(shù)據(jù)流的使用,需要的朋友可以參考下2023-08-08Vue使用Composition?API生成計算屬性computed
這篇文章主要為大家詳細(xì)介紹了Vue如何使用Composition?API實現(xiàn)生成計算屬性computed,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-06-06vue?router進(jìn)行路由跳轉(zhuǎn)并攜帶參數(shù)的實例詳解(params/query)
在使用`router.push`進(jìn)行路由跳轉(zhuǎn)到另一個組件時,可以通過`params`或`query`來傳遞參數(shù),這篇文章主要介紹了vue?router進(jìn)行路由跳轉(zhuǎn)并攜帶參數(shù)(params/query),需要的朋友可以參考下2023-09-09