詳解Vue3中偵聽(tīng)器watch的使用教程
上一節(jié)我們簡(jiǎn)單的介紹了一下 vue3 項(xiàng)目中的計(jì)算屬性,這一節(jié)我們繼續(xù) vue3 的基礎(chǔ)知識(shí)講解。
這一節(jié)我們來(lái)說(shuō) vue3 的偵聽(tīng)器。
學(xué)過(guò) vue2 的小伙伴們肯定學(xué)習(xí)過(guò)偵聽(tīng)器,主要是用來(lái)監(jiān)聽(tīng)頁(yè)面數(shù)據(jù)或者是路由的變化,來(lái)執(zhí)行相應(yīng)的操作,在 vue3里面呢,也有偵聽(tīng)器的用法,功能基本一樣,換湯不換藥的東西。 偵聽(tīng)器是常用的 Vue API 之一,它用于監(jiān)聽(tīng)一個(gè)數(shù)據(jù)并在數(shù)據(jù)變動(dòng)時(shí)做一些自定義邏輯,本文將先列舉偵聽(tīng)器在 Vue 中的使用方式,然后再分析源碼講述為什么可以這樣使用、以及偵聽(tīng)器的實(shí)現(xiàn)原理。下面我們稍微說(shuō)一下偵聽(tīng)器。
watch 偵聽(tīng)器使用。
watch API 使用,至少需要指定兩個(gè)參數(shù): sourc
e 和 callback
,其中 callback 被明確指定只能為函數(shù),所以不同是用方式的差別其實(shí)只在 source 。
接下來(lái)我們看一下 vue3 偵聽(tīng)器的基本使用:
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num" /> <br> <br> <el-button type="primary" @click="num++">num + 1</el-button> </div> </template> <script> import { watch, ref } from 'vue' export default { setup() { const num = ref(1) watch(num, (newVal, oldVal) => { console.log("新值:", newVal, " 舊值:", oldVal) }) return { num, } } } </script> <style scoped> .el-input { width: 100px; } </style>
上面的代碼是頁(yè)面上有一個(gè)數(shù)字,點(diǎn)擊按鈕一下,數(shù)字加一,然后偵聽(tīng)器偵聽(tīng)數(shù)字的變化,打印出偵聽(tīng)的最新值和老值。
OK。上邊的案例就是 vue3 偵聽(tīng)器的簡(jiǎn)單案例,偵聽(tīng)器和計(jì)算屬性一樣,可以創(chuàng)建多個(gè)偵聽(tīng)器,這個(gè)是沒(méi)有問(wèn)題的,案例就不寫了,和上一節(jié)講的聲明多個(gè)計(jì)算屬性是一致的。如果有不明白的可以看一下我的上一篇博客。
上邊我們說(shuō)過(guò)這么一句話,watch API 至少需要指定兩個(gè)參數(shù): source 和 callback。通過(guò)上邊的案例我們看到了, 確實(shí)是兩個(gè),source 是監(jiān)聽(tīng)的數(shù)據(jù),callback 是監(jiān)聽(tīng)回調(diào),那為啥說(shuō)是至少呢?
對(duì)的,因?yàn)樗€有第三個(gè)參數(shù) —— 配置對(duì)象。
在 vue2 里面,我們打開頁(yè)面就像讓偵聽(tīng)器立即執(zhí)行,而不是在第一次數(shù)據(jù)改變的時(shí)候才開始執(zhí)行,這時(shí)候有一個(gè)參數(shù)叫 immediate
,設(shè)置了這個(gè)參數(shù),創(chuàng)建第一次就執(zhí)行,所以說(shuō)呢,vue3 同樣可以使用。
上面的案例刷新執(zhí)行的時(shí)候發(fā)現(xiàn),在點(diǎn)擊按鈕之前,也就是 num 創(chuàng)建的時(shí)候,偵聽(tīng)器是沒(méi)有執(zhí)行的,所以說(shuō)呢,加上 immediate 參數(shù),就可以讓偵聽(tīng)器立即執(zhí)行操作。
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num" /> <br> <br> <el-button type="primary" @click="num++">num + 1</el-button> </div> </template> <script> import { watch, ref } from 'vue' export default { setup() { const num = ref(1) watch(num, (newVal, oldVal) => { console.log("新值:", newVal, " 舊值:", oldVal) }, { immediate: true }) return { num, } } } </script> <style scoped> .el-input { width: 100px; } </style>
我們看到,刷新完頁(yè)面,還沒(méi)有點(diǎn)擊按鈕讓 num 加一的,控制臺(tái)就有數(shù)據(jù)打印了,為什么呢?就是因?yàn)槲覀兗恿?immediate 為 true,讓偵聽(tīng)器立即執(zhí)行。控制臺(tái)輸出最新的值也就是我們初始化的值1,老的值沒(méi)有,所以輸出了 undefined。
偵聽(tīng)器監(jiān)聽(tīng) reactive
上面說(shuō)了偵聽(tīng)器偵聽(tīng)單個(gè)數(shù)據(jù),他也可以用來(lái)偵聽(tīng)對(duì)象的變化。
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.age++">num + 1</el-button> </div> </template> <script> import { watch, ref, reactive } from 'vue' export default { setup() { const num = reactive({ name: '我是????.', age: 10 }) watch(num, (newVal, oldVal) => { console.log(newVal, oldVal) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
比如說(shuō)上面代碼,我們偵聽(tīng) num 這個(gè)對(duì)象的變化。
看效果我們發(fā)下,在監(jiān)聽(tīng)整個(gè) reactive 響應(yīng)式對(duì)象的時(shí)候,確實(shí)當(dāng)里面的屬性值發(fā)生改變了之后可以被偵聽(tīng)器檢測(cè)到,但是 newVal 和 oldVal 的值都是新的,默認(rèn)是10,點(diǎn)擊之后,新值是 11 很正常,但是老值不應(yīng)該是 10 嗎?為什么這里老值和新值一樣也是 11 呢?
這個(gè)不需要疑問(wèn)哈,如果監(jiān)聽(tīng)整個(gè) reactive 數(shù)據(jù)的話,只能回調(diào)到最新的值,獲取不到老的值。
那問(wèn)題來(lái)嘍,我就修改 age 屬性,我就要獲取 age 老的值怎么辦?其實(shí)我們只需要監(jiān)聽(tīng) num 下面的 age 就可以了,先看下面的代碼哈。
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.age++">num + 1</el-button> </div> </template> <script> import { watch, ref, reactive } from 'vue' export default { setup() { const num = reactive({ name: '我是????.', age: 10 }) watch(num.age, (newVal, oldVal) => { console.log(newVal, oldVal) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
我們監(jiān)聽(tīng)對(duì)象直接是 num.age, 監(jiān)聽(tīng)年齡屬性值,保存看一下效果。
刷新結(jié)果我們可以看到哈,我們啥都沒(méi)干,偵聽(tīng)器直接報(bào)了一個(gè)警告給我們,啥意思呢,其實(shí)不能直接這樣監(jiān)聽(tīng)。
當(dāng)我們需要監(jiān)聽(tīng)某個(gè)對(duì)象屬性的時(shí)候,我們不能直接對(duì)象點(diǎn)屬性的方式進(jìn)行監(jiān)聽(tīng),需要傳入一個(gè) getter 方法,也就是箭頭函數(shù)進(jìn)行監(jiān)聽(tīng),下面的代碼是正確方式哈。
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.age++">num + 1</el-button> </div> </template> <script> import { watch, ref, reactive } from 'vue' export default { setup() { const num = reactive({ name: '我是????.', age: 10 }) watch(() => num.age, (newVal, oldVal) => { console.log(newVal, oldVal) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
OK,保存刷新,我們發(fā)現(xiàn),偵聽(tīng)器已經(jīng)不報(bào)錯(cuò)了,而且我們點(diǎn)擊按鈕讓 age 加一的時(shí)候,可以順利的監(jiān)聽(tīng)到 age 的變化,并且回調(diào)出最新值和上一次的值。
通過(guò)箭頭函數(shù),我們就可以實(shí)現(xiàn)對(duì)象屬性的監(jiān)聽(tīng)。
很多人說(shuō),vue2 在監(jiān)聽(tīng)對(duì)象的時(shí)候需要對(duì)偵聽(tīng)器設(shè)置深度偵聽(tīng),為什么 vue3 這個(gè)不需要呢?因?yàn)樗O(jiān)聽(tīng)響應(yīng)式對(duì)象,默認(rèn)就是深度監(jiān)聽(tīng)。但是,如果監(jiān)聽(tīng)的是深度嵌套對(duì)象或數(shù)組中的 property 變化時(shí),仍然需要 deep 選項(xiàng)設(shè)置為 true。
看下面的案例,我們監(jiān)聽(tīng)深層嵌套的 time 屬性值。其實(shí)我覺(jué)得沒(méi)大必要,不使用箭頭函數(shù)其實(shí)可以。但是還是寫一下吧。
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num.todo.time" /> <br> <br> <el-button type="primary" @click="num.todo.time ++">num.todo.time + 1</el-button> </div> </template> <script> import { watch, ref, reactive, computed, } from 'vue' export default { setup() { const num = reactive({ name: '我是????.', age: 10, todo: { name: '彈吉他', time: 1 } }) watch(() => num, (newVal, oldVal) => { console.log(newVal.todo.time, oldVal.todo.time) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
保存代碼刷新,發(fā)現(xiàn)點(diǎn)擊之后沒(méi)有監(jiān)聽(tīng)到。
這個(gè)時(shí)候就可以加上 deep 深度監(jiān)聽(tīng)。
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num.todo.time" /> <br> <br> <el-button type="primary" @click="num.todo.time ++">num.todo.time + 1</el-button> </div> </template> <script> import { watch, ref, reactive, computed, } from 'vue' export default { setup() { const num = reactive({ name: '我是????.', age: 10, todo: { name: '彈吉他', time: 1 } }) watch(() => num, (newVal, oldVal) => { console.log(newVal.todo.time, oldVal.todo.time) }, { deep: true }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
加上深度監(jiān)聽(tīng) { deep:true }
我們可以看到打印出信息來(lái)了,其實(shí)我覺(jué)得這個(gè)方法有點(diǎn)多余,但是萬(wàn)一用到呢是吧?啊哈哈哈哈,自己根據(jù)情況選擇使用吧。
但是有一點(diǎn)要注意哈!深度偵聽(tīng)需要遍歷被偵聽(tīng)對(duì)象中的所有嵌套的 屬性,當(dāng)用于大型數(shù)據(jù)結(jié)構(gòu)時(shí),開銷很大。因此請(qǐng)只在必要時(shí)才使用它,并且要留意性能。
監(jiān)聽(tīng)多個(gè)參數(shù)執(zhí)行各自邏輯
本來(lái)不打算說(shuō)了,但是逼逼賴賴這么久了,稍微簡(jiǎn)單提一下吧。
比如說(shuō)我們需要監(jiān)聽(tīng)多個(gè)參數(shù),假設(shè)兩個(gè)哈,然后每個(gè)參數(shù)監(jiān)聽(tīng)到之后,執(zhí)行的邏輯是不一樣的,我們可以創(chuàng)建多個(gè)偵聽(tīng)器來(lái)分別監(jiān)聽(tīng),不寫全部代碼了,只寫關(guān)鍵代碼了哈。
// 第一個(gè) watch(num, (newVal, oldVal) => { console.log(newVal, oldVal) }) // 第二個(gè) watch(()=> boy.age, (newVal, oldVal) => { console.log(newVal, oldVal) })
監(jiān)聽(tīng)多個(gè)參數(shù)執(zhí)行相同邏輯
這個(gè)的意思就是無(wú)論是 num 改變還是 boy.age 改變,我執(zhí)行的代碼都是一樣的??聪旅姘咐?/p>
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num.name" /> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.todo.time ++">num.todo.time + 1</el-button> </div> </template> <script> import { watch, ref, reactive, computed, } from 'vue' export default { setup() { const num = reactive({ name: '我是????.', age: 10, todo: { name: '彈吉他', time: 1 } }) watch([() => num.name, () => num.age], (newVal, oldVal) => { console.log(newVal, oldVal) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
保存刷新頁(yè)面,修改 name 和 age 的值。
上面我們把數(shù)據(jù)源以數(shù)組的方式傳入,返回的回調(diào)參數(shù),新值和舊值都是以數(shù)組的方式返回,新值舊值的數(shù)組內(nèi)順序就是我們數(shù)據(jù)源傳入的順序,都能看出來(lái)哈。
如果你不想讓他返回?cái)?shù)組你可以這樣改一下,其實(shí)都差不多,了解一下,根據(jù)實(shí)際情況選擇性使用就行。
<template> <div> <h1>watch 偵聽(tīng)器</h1> <el-input v-model="num.name" /> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.todo.time ++">num.todo.time + 1</el-button> </div> </template> <script> import { watch, ref, reactive, computed, } from 'vue' export default { setup() { const num = reactive({ name: '我是????.', age: 10, todo: { name: '彈吉他', time: 1 } }) watch([() => num.name, () => num.age], ([newName, newAge], [oldName, oldAge]) => { console.log(newName, newAge, oldName, oldAge) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
保存刷新查看一下效果。
以上就是詳解Vue3中偵聽(tīng)器watch的使用教程的詳細(xì)內(nèi)容,更多關(guān)于Vue3偵聽(tīng)器watch的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解vue父子組件關(guān)于模態(tài)框狀態(tài)的綁定方案
這篇文章主要介紹了詳解vue父子組件關(guān)于模態(tài)框狀態(tài)的綁定方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-06-06vue打包報(bào)錯(cuò):ERROR in static/js/xxx.js from U
這篇文章主要介紹了vue打包報(bào)錯(cuò):ERROR in static/js/xxx.js from UglifyJs undefined問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09解決vuejs 使用value in list 循環(huán)遍歷數(shù)組出現(xiàn)警告的問(wèn)題
今天小編就為大家分享一篇解決vuejs 使用value in list 循環(huán)遍歷數(shù)組出現(xiàn)警告的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09vue3二次封裝element-ui中的table組件的過(guò)程詳解
這篇文章主要給大家介紹了vue3二次封裝element-ui中的table組件的過(guò)程,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友跟著小編一起來(lái)學(xué)習(xí)吧2024-01-01在vue項(xiàng)目中設(shè)置一些全局的公共樣式
這篇文章主要介紹了在vue項(xiàng)目中設(shè)置一些全局的公共樣式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05