一、需求分析,問(wèn)題描述
1、需求
監(jiān)聽(tīng)數(shù)組或?qū)ο螅薷钠鋵傩詳?shù)據(jù),但watch并沒(méi)有監(jiān)聽(tīng)到變化,尋找原因和解決方式。
2、問(wèn)題
- 怎樣正確使用watch監(jiān)聽(tīng)對(duì)象和數(shù)組?
- 怎樣停止watch監(jiān)聽(tīng)?
二、解決問(wèn)題,答案速覽
1、Watch監(jiān)聽(tīng)器-監(jiān)聽(tīng)Ref
(1)監(jiān)聽(tīng)單個(gè)ref對(duì)象
對(duì)于單個(gè)ref對(duì)象的監(jiān)聽(tīng),我們只需要直接監(jiān)聽(tīng)即可,沒(méi)有套路。
<script setup>
import { reactive, ref, watch, computed } from 'vue';
// 定義數(shù)據(jù)
let nameRef = ref('大澈')
// 點(diǎn)擊事件-修改數(shù)據(jù)的值
const handleChange = () => {
nameRef.value = '程序員大澈'
}
// 監(jiān)聽(tīng)數(shù)據(jù)變化
watch(nameRef, (newValue, oldValue) => {
console.log(`新的值是:${newValue},舊的值是:${oldValue}`);
})
</script>
(2)監(jiān)聽(tīng)單個(gè)ref對(duì)象的值-基本類(lèi)型值
對(duì)于單個(gè)ref對(duì)象的基本類(lèi)型值的監(jiān)聽(tīng),我們需要借助getter函數(shù)監(jiān)聽(tīng)。直接監(jiān)聽(tīng)會(huì)報(bào)警告,并且監(jiān)聽(tīng)不到變化。
<script setup>
import { reactive, ref, watch, computed } from 'vue';
// 定義數(shù)據(jù)
let nameRef = ref('大澈')
// 點(diǎn)擊事件-修改數(shù)據(jù)的值
const handleChange = () => {
nameRef.value = '程序員大澈'
}
// 監(jiān)聽(tīng)數(shù)據(jù)變化
watch(() => nameRef.value, (newValue, oldValue) => {
console.log(`新的值是:${newValue},舊的值是:${oldValue}`);
})
</script>
(3)監(jiān)聽(tīng)單個(gè)ref對(duì)象的值-復(fù)雜類(lèi)型值
內(nèi)部自動(dòng)將值轉(zhuǎn)為reactive對(duì)象,監(jiān)聽(tīng)reactive對(duì)象的詳細(xì)見(jiàn)下文。
(4)監(jiān)聽(tīng)多個(gè)ref對(duì)象或其值
對(duì)于多個(gè)ref對(duì)象或其值的監(jiān)聽(tīng),我們需要使用數(shù)組將watch監(jiān)聽(tīng)器的目標(biāo)包裹。
<script setup>
import { reactive, ref, watch, computed } from 'vue';
// 定義數(shù)據(jù)
let nameRef111 = ref('大澈111')
let nameRef222 = ref('大澈222')
// 點(diǎn)擊事件-修改數(shù)據(jù)的值
const handleChange = () => {
nameRef111.value = '程序員大澈111'
nameRef222.value = '程序員大澈222'
}
// 監(jiān)聽(tīng)數(shù)據(jù)變化
watch([nameRef111, () => nameRef222.value], (newValue, oldValue) => {
console.log(`新的值是:${newValue[0]},舊的值是:${oldValue[0]}`);
})
</script>
2、Watch監(jiān)聽(tīng)器-監(jiān)聽(tīng)Reactive
(1)監(jiān)聽(tīng)單個(gè)reactive對(duì)象-對(duì)象類(lèi)型值
對(duì)于單個(gè)reactive對(duì)象的對(duì)象類(lèi)型值的監(jiān)聽(tīng),我們只需要直接監(jiān)聽(tīng)即可,沒(méi)有套路。
但此時(shí)我們會(huì)發(fā)現(xiàn),watch的新值和舊值是相同的,為什么會(huì)這樣呢?又怎么解決呢?
因?yàn)閷?duì)于引用類(lèi)型數(shù)據(jù),賦值存的是地址,地址指向的是堆,所以無(wú)論值怎么改變,新舊對(duì)象都指向同一個(gè)地址。
至于解決的辦法很簡(jiǎn)單, 我們不去直接監(jiān)聽(tīng)一個(gè)引用類(lèi)型,而是去監(jiān)聽(tīng)引用類(lèi)型中一個(gè)具體的值即可。
<script setup>
import { reactive, ref, watch, computed } from 'vue';
// 定義數(shù)據(jù)
let dataReactive = reactive({
name: '大澈',
})
// 點(diǎn)擊事件-修改數(shù)據(jù)的值
const handleChange = () => {
dataReactive.name = '程序員大澈'
}
// 監(jiān)聽(tīng)數(shù)據(jù)變化
watch(dataReactive, (newValue, oldValue) => {
console.log(`新的值是:${newValue.name},舊的值是:${oldValue.name}`);
})
</script>
(2)監(jiān)聽(tīng)單個(gè)reactive對(duì)象-對(duì)象類(lèi)型值-基本類(lèi)型屬性
對(duì)于單個(gè)reactive對(duì)象的對(duì)象類(lèi)型值的基本類(lèi)型屬性的監(jiān)聽(tīng),我們需要借助getter函數(shù)監(jiān)聽(tīng)。直接監(jiān)聽(tīng)會(huì)報(bào)警告,并且監(jiān)聽(tīng)不到變化。
值得注意的是,watch的新值和舊值是不同的了。
(3)監(jiān)聽(tīng)單個(gè)reactive對(duì)象-對(duì)象類(lèi)型值-對(duì)象類(lèi)型屬性
對(duì)于單個(gè)reactive對(duì)象的對(duì)象類(lèi)型值的對(duì)象類(lèi)型屬性的監(jiān)聽(tīng),我們需要借助getter函數(shù)監(jiān)聽(tīng)。直接監(jiān)聽(tīng)會(huì)報(bào)警告,并且監(jiān)聽(tīng)不到變化。
如果是監(jiān)聽(tīng)整個(gè)對(duì)象類(lèi)型屬性,只有進(jìn)行整個(gè)對(duì)象替換時(shí),才不需要開(kāi)啟deep深度監(jiān)聽(tīng)。其它時(shí)候,如修改、刪除、新增,都需要開(kāi)啟deep深度監(jiān)聽(tīng),才能監(jiān)聽(tīng)數(shù)據(jù)的變化。
如果是監(jiān)聽(tīng)對(duì)象類(lèi)型屬性中的某個(gè)屬性值,則不需要開(kāi)啟deep深度監(jiān)聽(tīng)。
<script setup>
import { reactive, ref, watch, computed } from 'vue';
// 定義數(shù)據(jù)
let dataReactive = reactive({
obj: {
age: 18,
},
})
// 點(diǎn)擊事件-修改數(shù)據(jù)的值
const handleChange = () => {
dataReactive.obj.age = 99
}
// 監(jiān)聽(tīng)數(shù)據(jù)變化
watch(() => dataReactive.obj, (newValue, oldValue) => {
console.log(`新的值是:${newValue.age},舊的值是:${oldValue.age}`);
}, {
deep: true,
})
</script>
(4)監(jiān)聽(tīng)單個(gè)reactive對(duì)象-對(duì)象類(lèi)型值-數(shù)組類(lèi)型屬性
同監(jiān)聽(tīng)單個(gè)reactive對(duì)象-對(duì)象類(lèi)型值-對(duì)象類(lèi)型屬性。
(5)監(jiān)聽(tīng)單個(gè)reactive對(duì)象-數(shù)組類(lèi)型值
所有情況都同監(jiān)聽(tīng)單個(gè)reactive對(duì)象-對(duì)象類(lèi)型值。
(6)監(jiān)聽(tīng)多個(gè)reactive對(duì)象值或其屬性值
同監(jiān)聽(tīng)多個(gè)ref對(duì)象或其值。
三、問(wèn)題解析,知識(shí)總結(jié)
1、怎樣正確使用watch監(jiān)聽(tīng)對(duì)象和數(shù)組?
內(nèi)容如上。
2、怎樣停止watch監(jiān)聽(tīng)?
有的時(shí)候,我們可能只需要監(jiān)聽(tīng)一次。在監(jiān)聽(tīng)之后,我們就需要取消對(duì)watch的監(jiān)聽(tīng)。此時(shí)我們可以這樣做,將watch監(jiān)聽(tīng)器賦值給一個(gè)變量,在取消監(jiān)聽(tīng)的時(shí)候調(diào)用此變量即可。
<script setup>
import { reactive, ref, watch, computed } from 'vue';
// 定義數(shù)據(jù)
let nameRef = ref('大澈')
// 點(diǎn)擊事件-修改數(shù)據(jù)的值
const handleChange = () => {
nameRef.value = '程序員大澈'
}
// 點(diǎn)擊事件-停止對(duì)應(yīng)的watch監(jiān)聽(tīng)數(shù)據(jù)
const handleStopChange = () => {
stopWatch()
}
// 監(jiān)聽(tīng)數(shù)據(jù)變化
const stopWatch = watch(() => nameRef.value, (newValue, oldValue) => {
console.log(`新的值是:${newValue},舊的值是:${oldValue}`);
})
</script>