前言 在Vue.js我們常常會使用watch來做一些對應處理,例如可以監控某值出現變化的時候,就觸發function去做事情,有時候我們也會需要拿到變化前的值或變化後的值去做利用。此篇我們來探討一下watch機制如何運作。
監控ref定義的響應式數據 請特別注意,這邊提到的是數據,不是物件
1 2 3 4 5 6 7 8 9 10 11 12 13 <script setup> import { ref, watch } from 'vue' const sum = ref (0 )watch (sum,(newVal,oldVal ) => { console .log ("newVal" ,newVal) console .log ("oldVal" ,oldVal) }) </script> <template > {{sum}} <button @click ="sum++" > click</button > </template >
點擊一下,查看主控台(F12>>console)會印出1和0的值 再點一下newVal和oldVal則再往上累加。 代表監控ref定義的響應式數據
可以直接針對ref進行監控
可以成功印出新值和舊值
監控ref定義的多個響應式數據 用陣列將要監控的ref裝起來
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <script setup> import { ref, watch } from 'vue' const sum = ref (0 )const message= ref ('你好啊' )watch ([sum,message],(newVal,oldVal ) => { console .log ("newVal" ,newVal) console .log ("oldVal" ,oldVal) }) </script> <template > {{sum}} {{message}} <button @click ="sum++" > sum click</button > <button @click ="message += '~'" > message click</button > </template >
點選sum click按鈕會印出以下結果
監控reactive所定義的一個響應式物件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <script setup> import { reactive, watch } from 'vue' const person = reactive ({ name : 'fred' , age : 18 }) watch (person, (newVal, oldVal ) => { console .log ("newVal" , newVal) console .log ("oldVal" , oldVal) }) </script> <template > {{ person.age }} <button @click ="person.age++" > click</button > </template >
點選click按鈕會印出以下結果 我們會發現newVal的age值變成19了,oldVal竟然也是相同值(因指向同一個對象,共用一份記憶體),代表我們無法取得oldVal的值,這一點要特別留意,不過我們一般的需求也還真的鮮少拿舊的值去做運用,所以影響並沒有太大。
註:reactive也能改為ref,但監控對象就要改寫為person.value,才能偵測到裡面值的變化
監控reactive所定義的一個響應式數值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <script setup> import { reactive, watch } from 'vue' const person = reactive ({ name : 'fred' , age : 18 }) watch (person.age , (newVal, oldVal ) => { console .log ("newVal" , newVal) console .log ("oldVal" , oldVal) }) </script> <template > {{ person.age }} <button @click ="person.age++" > click</button > </template >
瀏覽器會直接報出警告A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types. 意思是說,watch能監控的對象只能是 getter函式、ref對象、reactive物件對象、陣列,所以上述例子person.age是單純的值是無法監控的,所以要做監控的話我們可以包裝成getter函式,改寫成以下
1 2 3 4 watch (()=> person.age ,(newVal,oldVal )=> { console .log ("newVal" , newVal) console .log ("oldVal" , oldVal) })
按下click後印出以下結果
這樣就能順利監控到person.age的值了
註:reactive也能改為ref,但監控對象就要改成()=>person.value.age,才能偵測到裡面值的變化
為什麼有時候ref對象要加上.value,有時候不用,判斷標準是什麼 依據對象型態而定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <script setup> import { ref, watch } from 'vue' const sum = ref (0 )const person = ref ({ name : 'fred' , age : 18 , job : { m1 : { salary : 20 } } }) watch (sum, (newVal, oldVal ) => { console .log ("newVal" , newVal) console .log ("oldVal" , oldVal) }) watch (person.value , (newVal, oldVal ) => { console .log ("newVal" , newVal) console .log ("oldVal" , oldVal) }) </script> <template > {{ sum }} <button @click ="sum++" > click</button > <br > {{ person.job.m1.salary }} <button @click ="person.job.m1.salary++" > click</button > </template >
像sum的話是一個基本類型數字型態用ref包裝起來的,就不用額外加上.value,因為加上.value就是指裡面0的值,是無法作監控的。 如果是person因為他是一個物件用ref包裝,裡面的屬性值變化時,需要偵測我們就必須監控person.value的值,就是針對Proxy物件來監控,就能偵測到變化。 另外一提,假若現在真的不想要.value,則可將watch改寫為以下,加上{deep:true}做深層監控,也是能監控到最新的值,如何使用還是看個人習慣。
1 2 3 4 watch (person, (newVal, oldVal ) => { console .log ("newVal" , newVal) console .log ("oldVal" , oldVal) }, { deep : true })
上述範例重點整理
如果是基本型態的資料要監控,可用getter函式返回
監控reactive和ref概念一樣,只是要注意ref對象要記得加上.value,加上.value就是等同於reactive對象,就是Proxy物件
承上,如果ref不要用.value處理,則要用{ deep: true }做深層監控,就能監控到
reactive對象,強制會用深層監控,不用加{ deep: true }
參考資料:官網