1、watch概述
watch本意是监视、观察。它的功能就是监视数据的变化。数据一旦变化,就会产生两种数据:新数据、旧数据。 如业务场景中,当订单量大多某个数时,就发放优惠卷。watch非常重要,掌握好响应式数据、computed、watch,vue写功能不会有太大问题。 在vue官网明确表达,watch可以监视以下四种数据:
- ref定义的数据
- reactive定义的数据
- 函数返回一个值(
getter函数) - 包含上诉三种值的数组
2、监视ref定义的基本类型数据
- 创建组件Fish
- 引入ref、watch
- 创建响应式数据name、price
- watch函数监视price变化
- 当price超过10,watch停止监视price变化
<template>
<h2>鱼类:{{ name }}</h2>
<h2>价格:{{ price }}</h2>
<button @click="addPrice()">增加价格</button>
</template>
<script setup>
import { ref, watch } from 'vue'
let name = ref('鲫鱼');
let price = ref(5);
function addPrice() {
price.value += 1;
}
let stopWatchPrice = watch(price, (newValue, oldValue) => {
console.log(newValue, oldValue);
if (newValue > 10) {
console.log(stopWatchPrice);
stopWatchPrice.stop();
}
})
</script>
运行效果事例:
注意watch函数,监视的是
price,而不是price.value。当点击按钮,price超过10,虽然数据在增加,但不再监视price。watch函数返回对象,有stop函数,调用此函数,即可解除监视。控制台打印,其结构如下:
() => {
effect2.stop();
if (scope && scope.active) {
remove(scope.effects, effect2);
}
}
3、监视ref定义的对象类型数据
监视对象类型的数据,与基础类型的数据不同。当对象中的数据变化时,是无法监视到,但当整个数据改变时,是可以监视的。特点如下:
- 创建组件Fish,引入ref、watch
- 创建响应式对象fish,let fish = ref({ name: '鲫鱼', price: 5 });
- 当改变
fish.name值时,无法监视fish的变化 - 当改变
fish.price值时,无法监视fish的变化 - 当改变整条鱼时,能够监视fish变化
<template>
<h2>鱼类:{{ fish.name }}</h2>
<h2>价格:{{ fish.price }}</h2>
<button @click="changeName()">修改鱼类</button>
<button @click="changePrice()">修改鱼价</button>
<button @click="changeFish()">更换真个鱼</button>
</template>
<script setup>
import { ref, watch } from 'vue'
let fish = ref({ name: '鲫鱼', price: 5 });
function changeName() {
fish.value.name += '~';
}
function changePrice() {
fish.value.price += 1;
}
function changeFish() {
fish.value = { name: '鲤鱼', price: 10 };
}
watch(fish, (newValue, oldValue) => {
console.log(newValue, oldValue);
})
运行效果如下:
当修改响应式对象成员变量时,不会引起fish watch函数运行。原因在于watch监视的不是
fish.name而是fish。那么如何才能监视fish.name与fish.price数据变化呢?
watch函数,它有三个参数
- 一是监视对象
- 二是监视回调函数,
- 三是配置对象参数,如deep等等 只有在配置对象开启deep即可。
<template>
<h2>鱼类:{{ fish.name }}</h2>
<h2>价格:{{ fish.price }}</h2>
<button @click="changeName()">修改鱼类</button>
<button @click="changePrice()">修改鱼价</button>
<button @click="changeFish()">更换真个鱼</button>
</template>
<script setup>
import { ref, watch } from 'vue'
let fish = ref({ name: '鲫鱼', price: 5 });
function changeName() {
fish.value.name += '~';
}
function changePrice() {
fish.value.price += 1;
}
function changeFish() {
fish.value = { name: '鲤鱼', price: 10 };
}
watch(fish, (newValue, oldValue) => {
console.log(newValue, oldValue);
}, { deep: true })
</script>
运行效果,仔细观看控制台打印的新数据、旧数据。
- 当
fish.name改变时,新旧数据一样 - 当
fish.price改变时,新旧数据一样 - 当fish整个改变时,新旧数据不一样
效果如图:
注意
fish.name与fish.price,新旧数据是一样的。因为watch是从对象地址取到的数据。
4、watch监视函数返回一个值(getter函数)
它的功能是wath监视响应式对象中一个属性,如监视fish.name,是不允许直接监视,需要写成一个函数的形式。
- 创建组件Fish,引入reactive, watch
- 创建响应式对象fish,鱼的名字,鱼的体型:长度、重量
- 分别监听鱼的名字与体型
- 点击按钮修改鱼类,鱼的长度、鱼的重量、鱼的体型
<template>
<h2>鱼类:{{ fish.name }}</h2>
<h2>鱼长度:{{ fish.body.long }}</h2>
<h2>鱼重量:{{ fish.body.weight }}</h2>
<button @click="changeName()">修改鱼类</button>
<button @click="changeFishLong()">修改鱼的长度</button>
<button @click="changeFishWeight()">修改鱼的重量</button>
<button @click="changeFishbody()">修改鱼的体型</button>
</template>
<script setup>
import { reactive, watch } from 'vue'
let fish = reactive({ name: '鲫鱼', body: { long: 1, weight: 24 } });
function changeName() {
fish.name += '~';
}
function changeFishLong() {
fish.body.long += 1;
}
function changeFishWeight() {
fish.body.weight += 1;
}
function changeFishbody() {
fish.body = { long: 100, weight: 300 };
}
watch(() => { return fish.name }, (newValue, oldValue) => {
console.log('监听fish.name', newValue, oldValue);
})
watch(() => { return fish.body }, (newValue, oldValue) => {
console.log('监听fish.body', newValue, oldValue);
})
</script>
监听响应式对象中的参数,需要写成一个箭头函数,并返回监听参数即可。具体操作,看下图:
当点击按钮,发现只有修改鱼类、修改鱼的体型,才能监听到变化。这是因为watch监听的地址。若想要能够监听到鱼的长度、鱼的重量,需要再watch加入deep参数即可。
watch(() => { return fish.body }, (newValue, oldValue) => {
console.log('监听fish.body', newValue, oldValue);
}, { deep: true })
注意点击按钮修改鱼的长度、修改鱼的重量,新旧数据是一致的。
5、watch监视含有响应式对象数组的数据
watch监视的对象是一个数组,数组内可以是ref定义基本类型数据,也可是对象,可以是函数。
watch([() => { return fish.name },() => { return fish.body }], (newValue, oldValue) => {
console.log('监听素组', newValue, oldValue);
}, { deep: true })
由于使用配置参数deep,操作效果如下:
具体代码
<template>
<h2>鱼类:{{ fish.name }}</h2>
<h2>鱼长度:{{ fish.body.long }}</h2>
<h2>鱼重量:{{ fish.body.weight }}</h2>
<button @click="changeName()">修改鱼类</button>
<button @click="changeFishLong()">修改鱼的长度</button>
<button @click="changeFishWeight()">修改鱼的重量</button>
<button @click="changeFishbody()">修改鱼的体型</button>
</template>
<script setup>
import { reactive, watch } from 'vue'
let fish = reactive({ name: '鲫鱼', body: { long: 1, weight: 24 } });
function changeName() {
fish.name += '~';
}
function changeFishLong() {
fish.body.long += 1;
}
function changeFishWeight() {
fish.body.weight += 1;
}
function changeFishbody() {
fish.body = { long: 100, weight: 300 };
}
watch([() => { return fish.name },() => { return fish.body }], (newValue, oldValue) => {
console.log('监听素组', newValue, oldValue);
}, { deep: true })
</script>
6、总结 watch可以监视四种数据,再加上配置函数,内容多且难记。在项目中多练习几次就能熟记。
- ref定义的数据
- reactive定义的数据
- 函数返回一个值(
getter函数) - 包含上诉三种值的数组 在现实开发中,第一种和第三种情况最常用。尤其第三种情况,加函数,加配置参数deep。属于重中之重。
watch(() => { return fish.body }, (newValue, oldValue) => {
console.log('监听fish.body', newValue, oldValue);
}, { deep: true })