5.1 watch概述
效果:监督数据的改动(和Vue2中的watch效果一致)
特色:Vue3中的watch只能监督以下四种数据:
ref
界说的数据。reactive
界说的数据。- 函数回来一个值(
getter
函数)。- 一个包含上述内容的数组。
5.2 监听ref根本类型
1、Vue2
关于根本类型的监听,Vue2便是一个函数,里边有newValue和oldValue回来新值和旧值。
watch: {
sum(newValue, oldValue) {
......
}
}
2、Vue3
在Vue3里运用watch要先import引入,而且watch里边传入两个参数:榜首个是监督的特点名,第二个是回调函数。
import {watch} from 'vue'
watch(sum, (newValue, oldValue) => {
......
})
这儿举一个最简略的比如:点按钮,数字+1。数字属于根本类型,咱们对它进行监听:
<template>
<div class="person">
<h2>当前求和为:{{sum}}</h2>
<button @click="changeSum">点我sum+1</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,watch} from 'vue'
// 数据
let sum = ref(0)
// 办法
function changeSum(){
sum.value += 1
}
watch(sum,(newValue,oldValue)=>{
console.log('sum改动了', newValue, oldValue)
})
</script>
留意:watch的榜首个参数传的是变量名,而不是它的value值,千万不要写成变量名.value。虽然它是ref类型,真正的值是.value,但watch并非监听它的value值。
5.3 监听ref目标类型
先回顾一下Vue2监听目标的语法,它是一个目标,里边经过handler办法来获取新值和旧值。
watch: {
sum: {
handler(newValue, oldValue) {
......
}
}
}
Vue3假如监听的是一个目标类型,这个比较有意思,它会呈现两种状况:榜首个监听的是整个目标的地址是否改动;第二个是监听目标里的特点是否产生改动。
5.3.1 监听目标地址
监听整个目标地址是否产生改动,这个是最简略的,直接把目标放进去watch监听就能够了。
鄙人面的比如里有3个按钮,”修正姓名”和”修正年纪”都是改动目标里的特点值,而”修正整个人”是改动整个目标。
<template>
<div class="person">
<h2>姓名:{{ person.name }}</h2>
<h2>年纪:{{ person.age }}</h2>
<button @click="changeName">修正姓名</button>
<button @click="changeAge">修正年纪</button>
<button @click="changePerson">修正整个人</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,watch} from 'vue'
// 数据
let person = ref({
name:'张三',
age:18
})
// 办法
function changeName(){
person.value.name += '~'
}
function changeAge(){
person.value.age += 1
}
function changePerson(){
person.value = {name:'李四',age:90}
}
watch(person,(newValue,oldValue)=>{
console.log('person改动了',newValue,oldValue)
})
</script>
咱们发现,直接把目标放进去watch进行监听,它是无法监听内部特点的改动的,它只能监听整个目标有没有被从头赋值,也便是它的地址有没有改动。
5.3.2 监听目标特点
在实践的开发中,咱们更多的是监听目标里的特点改动。此刻需求手动敞开深度监听,也便是设置deep: true。
咱们在这儿持续做Vue2与Vue3的语法对比:
1、Vue2
在Vue2中,需求深度监听,只需求在与handler平级的地方设置deep:true即可。
watch: {
person: {
handler(newValue, oldValue) {
......
},
deep: true
}
}
2、Vue3
在Vue3中,它相同是设置deep:true,区别就在于它是在watch的第三个参数里设置,第三个参数是一个目标,用来设置watch的一些配置项,比方{deep: true}。
watch(person,(newValue,oldValue)=>{
console.log('person改动了',newValue,oldValue)
}, {
deep: true
})
咱们发现,设置了deep:true深度监听之后,不管是特点值产生改动,仍是整个目标产生改动,它相同能监听得到。
当然除了deep:true之外,还有immediate:true也是比较常用,这个是当即监听的意思,它是先履行监听的函数,因此在初始化数据的时分,它就会当即调用一次watch监听。它的效果跟Vue2是完全一致的,在这儿就不再举例详述。
留意:咱们在监听目标的时分,假如是整个目标产生改动,那么它是能够辨认新目标与旧目标的。但假如目标不变,只是内部的特点产生改动,那么它的newValue与oldValue是一致的。
5.3.3 示例代码
请翻开F12控制台观看打印输出信息。
5.4 监听reactive目标类型
5.4.1 reactive与ref的监听对比
reactive只能界说目标类型,它不像ref那样能够界说根本和目标两种类型。reactive与ref在监听的时分,主要有以下两点区别:
1、reactive类型是不允许改动整个目标的,也便是说不能给它赋值一个新目标,因此它就不会呈现监听整个目标产生改动的状况
2、默认敞开深度监听
5.4.2 监听reactive
其实监听reactive跟ref是相同的,也是把目标传进去watch里进行监听,不过它比ref更加便利,直接就能够监听到里边的特点改动,不需求设置deep:true。准确来说是Vue3强行设置深度监听,哪怕你设置deep:false也是没用的。
<template>
<div class="person">
<h2>姓名:{{ person.name }}</h2>
<h2>年纪:{{ person.age }}</h2>
<button @click="changeName">修正姓名</button>
<button @click="changeAge">修正年纪</button>
<button @click="changePerson">修正整个人</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,watch} from 'vue'
// 数据
let person = reactive({
name:'张三',
age:18
})
// 办法
function changeName(){
person.name += '~'
}
function changeAge(){
person.age += 1
}
function changePerson(){
Object.assign(person,{name:'李四',age:80})
}
watch(person,(newValue,oldValue)=>{
console.log('person改动了',newValue,oldValue)
})
</script>
留意:示例中修正整个人(整个目标),它实践上是运用了Object.assign()办法,这个办法实践上并没有改动目标地址,它只不过是批量改动目标的各个特点而已。
5.4.3 示例代码
请翻开F12控制台观看打印输出信息。
5.5 监听目标特点
除了监听整个目标以外,还能够指定监听目标的某一个特点。而目标里的特点,又能够分成两种类型:一个是根本类型的特点,一个是目标类型的特点。
上述比如中,前面两个按钮是修正目标里的根本类型,后边3个按钮是修正目标里的目标类型,咱们对此逐个剖析:
5.5.1 根本类型特点
1、Vue2
在Vue2中,监听目标里的根本类型特点,以目标.特点用一个函数回来最新值和旧值。
watch: {
'person.name'(newValue, oldValue) {
......
}
}
2、Vue3
在Vue3监听一个目标,是直接把目标放进去watch里监听即可。现在要监听目标里的特点,咱们的榜首反应就会把目标.特点放进去监听。
例如在比如中想监听目标的姓名,很简略就会写成watch(person.name, ()=>{}),如下所示:
<template>
<div class="person">
<h2>姓名:{{ person.name }}</h2>
<h2>年纪:{{ person.age }}</h2>
<h2>轿车:{{ person.car.c1 }}、{{ person.car.c2 }}</h2>
<button @click="changeName">修正姓名</button>
<button @click="changeAge">修正年纪</button>
<button @click="changeC1">修正榜首台车</button>
<button @click="changeC2">修正第二台车</button>
<button @click="changeCar">修正整个车</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,watch} from 'vue'
// 数据
let person = reactive({
name:'张三',
age:18,
car:{
c1:'奔驰',
c2:'宝马'
}
})
// 办法
function changeName(){
person.name += '~'
}
......
watch(person.name, (newValue,oldValue) => {
console.log('person.name改动了',newValue,oldValue)
})
</script>
咱们发现,咱们直接以目标.特点的方法放进去监听,Vue3是不允许的,它会宣布警告:这是一个无效的监听源,它只允许以下四种类型:getter函数、ref类型、reactive类型、以上3种类型组合的数组。
明显这个person.name只不过是一个字符串,属于根本类型特点,并非以上四种类型之一。
那么getter函数又是什么呢,其实这个警告说得比较含糊,反而官方文档说得非常接地气:所谓getter函数,它便是回来一个值的函数。
文档地址:cn.vuejs.org/api/reactiv…
已然了解了getter函数,那么咱们只需求运用箭头函数将目标特点包裹一下就能够了:
watch(() => person.name, (newValue,oldValue) => {
console.log('person.name改动了',newValue,oldValue)
})
此刻它就只监听目标的name特点,其它特点都不会监听:
5.5.2 目标类型特点
1、Vue2
Vue2监听目标里的目标类型特点,其实跟监听一般目标是相同的,以目标.特点作为键,经过handler办法来获取新值和旧值。
watch: {
'person.car': {
handler(newValue, oldValue) {
......
}
}
}
2、Vue3
Vue3关于目标里的目标类型特点的监听,它有两种方法:一是直接监听,二是运用箭头函数包裹后再监听。
(1)直接监听特点目标
根本类型需求箭头函数包裹成getter函数才干监听,而目标类型不需求,它直接传入watch即可监听。
let person = reactive({
name:'张三',
age:18,
car:{
c1:'奔驰',
c2:'宝马'
}
})
function changeC1(){
person.car.c1 = '奥迪'
}
function changeC2(){
person.car.c2 = '群众'
}
function changeCar(){
person.car = {c1:'雅迪',c2:'爱玛'}
}
watch(person.car,(newValue,oldValue)=>{
console.log('person.car改动了',newValue,oldValue)
})
这儿能够看出一个问题,把特点目标直接传入watch监听,它能够监听到目标里每一个特点的改动,可是假如整个目标产生改动,也便是给它赋值一个新的目标,它是无法监听的。
(2)箭头函数包裹特点目标(引荐)
除了直接监听,还能够像根本类型那样先包裹一个箭头函数,再进行监听:
watch(() => person.car,(newValue,oldValue)=>{
console.log('person.car改动了',newValue,oldValue)
})
包裹了箭头函数之后,它反而无法监听里边的特点改动,它只重视目标的地址是否产生改动。假如想既监听内部特点,也监听目标地址,只需求再加上深度监听特点即可,即设置deep:true。
watch(() => person.car,(newValue,oldValue)=>{
console.log('person.car改动了',newValue,oldValue)
}, {deep: true})
5.5.3 示例代码
请翻开F12控制台观看打印输出信息。
5.6 监听多个数据
Vue3它能够一起监听多个数据,不需求分隔写多个watch,能够写在一个watch里,将需求监听的特点放进数组里传入watch监听即可。
这儿仍是举上述的比如,这次监听的是姓名和轿车这两个特点,但不监听年纪特点:
let person = reactive({
name:'张三',
age:18,
car:{
c1:'奔驰',
c2:'宝马'
}
})
function changeC1(){
person.car.c1 = '奥迪'
}
function changeC2(){
person.car.c2 = '群众'
}
function changeCar(){
person.car = {c1:'雅迪',c2:'爱玛'}
}
watch([()=>person.name,person.car],(newValue,oldValue)=>{
console.log('person.car改动了',newValue,oldValue)
})
留意:由于你是一起监听多个特点,因此里边只要某一个特点产生了改动,它都会触发。你传入的是数组,因此它也会回来整个数组,里边便是各个特点的值。
请翻开F12控制台观看打印输出信息。
5.7 免除watch监听
咱们一旦运用了watch,它就会永久监听,咱们相同有办法将这个监听免除去。
在watch调用的时分,实践上它是有回来值的,咱们能够运用变量接纳并打印观察一下:
const stopWatch = watch(sum,(newValue,oldValue)=>{
......
})
console.log(stopWatch)
咱们发现它其实是一个函数来的,假如咱们想停止监听,只需求履行它即可。
举一个比如,假定sum从0开始累加1,当大于10的时分撤销监听。
<template>
<div class="person">
<h2>当前求和为:{{sum}}</h2>
<button @click="changeSum">点我sum+1</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,watch} from 'vue'
// 数据
let sum = ref(0)
// 办法
function changeSum(){
sum.value += 1
}
const stopWatch = watch(sum,(newValue,oldValue)=>{
console.log('sum改动了',newValue,oldValue)
if(newValue >= 10){
stopWatch()
}
})
</script>
请翻开F12控制台观看打印输出信息。
5.8 watchEffect
5.8.1 watchEffect与watch的区别
1、都能监听响应式数据的改动,不同的是监听数据改动的方法不同
2、watch:要明确指出监听的数据,它是一个惰性监听,你不指定它就不监听
3、watchEffect:不必明确指出监听的数据(函数中用到哪些特点,那就监听哪些特点)。
5.8.2 watchEffect的运用
咱们相同用一个简略的比如做一个比较,假定有一个需求:当水温到达60度,或水位到达80cm时,给服务器发恳求。
1、watch完成方法
watch有多种监听方法,能够对水温文水位分别监听,也能够一起监听。这儿咱们运用最方便的方法,运用数组一起监听俩特点:
watch([temp,height],(value)=>{
// 从value中获取最新的水温(newTemp)、最新的水位(newHeight)
let [newTemp,newHeight] = value
// 逻辑
if(newTemp >= 60 || newHeight >= 80){
console.log('给服务器发恳求')
}
})
在这个需求里,触及到的变量总共是两个,分别是水温文水位,因此watch需求监听这两个特点才干完成。假如需求很杂乱,触及的变量有10个,那么你也只能老老实实的给watch指定这10个变量的监听。
2、watchEffect完成方法
watchEffect它不需求你去指定具体监听的特点,你只需求重视事务逻辑,只要代码触及到的变量,它会帮你自动监听。
假如用watchEffect来完成上面的需求,将会省去一切监听的特点,变得更加简洁和灵活。
watchEffect(()=>{
if(temp.value >= 60 || height.value >= 80){
console.log('给服务器发恳求')
}
})
3、watchEffect的瑕疵
假如在if条件里运用了或运算符||,它会依照条件顺序进行监听,一旦前面的条件契合,则后续的条件将不会监听。
持续用上面的比如:当水温到达60度,或水位到达80cm时,给服务器发恳求。咱们的代码写成if(temp.value >= 60 || height.value >= 80),依照咱们的理解,不管是temp仍是height变量,只要哪一个条件契合它都会触发。
但watchEffect的机制并非如此,它认为榜首个条件是temp是否大于60,假如契合,则height的值不管是多少它都不关心。它只有在榜首个条件不契合的状况下,它才会重视第二个条件。
因此大家在运用watchEffect写逻辑的时分,要小心运用||运算符,假如真实想在watchEffect完成if的或运算符,能够多写一个if来奇妙的绕开或运算符。
watchEffect(()=>{
if (temp.value >= 60) {
console.log('给服务器发恳求')
}
if (height.value >= 80 && temp.value < 60) {
console.log('给服务器发恳求')
}
})
上面的代码将if(temp.value >= 60 || height.value >= 80)拆分成两段,假如水温temp大于60就发恳求,假如水位超过80且水温不到60也发恳求(由于水温到60就不必考虑水位了)。这样也相同能完美完成咱们的需求。
5.8.3 watchEffect的留意事项
1、watchEffect是当即监听的,相当于watch配置了immediate为true相同
2、watchEffect不管是根本类型仍是目标类型,它都能够监听到
3、watchEffect的免除监听方法跟watch是相同的
5.8.4 示例代码
请翻开F12控制台观看打印输出信息。