31. Vue偵聽器Watch
1. 定義
Watch
是Vue.js
提供的一個觀察者模式谍倦,用于監(jiān)聽數(shù)據(jù)的變化并執(zhí)行相應(yīng)的回調(diào)函數(shù)葵腹。雖然計算屬性Computed
在大多數(shù)情況下更合適念秧,但有時也需要一個自定義的偵聽器Watch
冕臭。因為在有些情況下墓猎,我們需要在狀態(tài)變化時執(zhí)行一些“副作用”:例如更改 DOM胡诗,或是根據(jù)異步操作的結(jié)果去修改另一處的狀態(tài)邓线。
2. 基本用法
在Vue組件中,我們可以使用watch
來監(jiān)聽數(shù)據(jù)的變化并執(zhí)行回調(diào)函數(shù)煌恢,示例如下:
<template>
<div>
<div><label for="qu">問題: </label><input type="text" id="qu" placeholder="請輸入問題" v-model="question"></div>
<div>{{ answer }}</div>
</div>
</template>
<!-- vue2 -->
<script>
import axios from "axios"
export default {
data() {
return {
question: '',
answer: "no answer"
}
},
watch:{
question(newValue, oldValue) {
this.answer = "Thinking..."
this.debounceGet()
}
},
created() {
// 接收防抖獲取數(shù)據(jù)函數(shù)
this.debounceGet = this.debounce(this.getAnswer, 500)
},
methods:{
// 調(diào)用接口獲取數(shù)據(jù)
async getAnswer() {
try{
const res = await axios.get('https://yesno.wtf/api')
this.answer = await res.data.answer
} catch(error) {
this.answer = error
}
},
// 防抖函數(shù)控制
debounce(fn, wait) {
let timer = null
return function() {
if(timer)clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, wait);
}
}
}
}
</script>
<!-- vue3 -->
<script setup>
import axios from "axios"
import { ref, watch } from "vue"
const question = ref("")
const answer = ref("no answer")
// 異步獲取數(shù)據(jù)
const getAnswer = async() => {
try{
const res = await axios.get('https://yesno.wtf/api')
answer.value = await res.data.answer
} catch(error) {
answer.value = error
}
}
// 防抖函數(shù)
const debounce = (fn, wait) => {
let timer = null
return function() {
if(timer)clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, wait);
}
}
// 接收防抖獲取數(shù)據(jù)函數(shù)
const debounceGet = debounce(getAnswer, 500)
// 偵聽器
watch(question, (newValue, oldValue) => {
answer.value = "Thinking..."
debounceGet()
})
</script>
3. watch高級用法
watch
偵聽器還有三個屬性:
-
handler
:watch
中需要具體執(zhí)行的方法骇陈。 -
immediate
:在組件初始化時立即執(zhí)行hanler中代碼。 -
deep
:深度監(jiān)聽瑰抵,可以監(jiān)聽對象或數(shù)組內(nèi)部屬性的變化你雌。
<!-- vue2 -->
<script>
export default {
data() {
return {
obj: {
name: "Jack",
age: 20
}
}
},
watch:{
obj: {
handler(newValue, oldValue){
console.log("obj被改變");
},
immediate: true,
deep: true
}
},
methods:{
setName(){
this.obj.name = "Jarry"
}
}
}
</script>
在vue3中,直接給 watch()
傳入一個響應(yīng)式對象谍憔,會隱式地創(chuàng)建一個深層偵聽器——該回調(diào)函數(shù)在所有嵌套的變更時都會被觸發(fā):
// vue3
const obj = reactive({
name: "Jack",
age: 20
})
const setName = () => {
obj.name = "Bob"
}
//直接傳入響應(yīng)式對象匪蝙,所有子孫元素改變都會偵聽到,默認(rèn)深度監(jiān)聽
watch(obj, (newValue, oldValue) => {
console.log("obj被改變");
})
//傳入一個getter函數(shù)习贫,只會偵聽到對應(yīng)的屬性的變化逛球,默認(rèn)深度監(jiān)聽
watch(() => obj.name, (newValue, oldValue) => {
console.log("obj.name被改變");
})
// 傳入deep屬性,強制監(jiān)聽
watch(() => obj.age, (newValue, oldValue) => {
console.log("obj.age被改變");
}, { deep: true })
setName();//obj被改變
obj.age++
watch
默認(rèn)是懶執(zhí)行的:僅當(dāng)數(shù)據(jù)源變化時苫昌,才會執(zhí)行回調(diào)颤绕。但在某些場景中,我們希望在創(chuàng)建偵聽器時祟身,立即執(zhí)行一遍回調(diào)奥务。舉例來說,我們想請求一些初始數(shù)據(jù)袜硫,然后在相關(guān)狀態(tài)更改時重新請求數(shù)據(jù)氯葬。
我們可以通過傳入 immediate: true
選項來強制偵聽器的回調(diào)立即執(zhí)行:
// 傳入immediate, 立即執(zhí)行
watch(obj, (newValue, oldValue) => {
console.log("立即執(zhí)行");
}, { immediate: true })