Watch
什么是watch
watch 的作用是用于监测响应式属性的变化,并在属性发生改变时执行特定的操作,它是 Vue 中的一种响应式机制,允许你在数据发生变化时做出相应的响应,执行自定义的逻辑。
watch 使得在响应式属性变化时能够有更多的控制权和灵活性,让你的组件能够更好地响应数据的变化并执行相应的逻辑。
watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。
监听数据类型
1.一个 ref() 定义的响应式数据
2. 一个 reactive() 定义的响应式数据
3. 一个getter 函数,返回一个值
4. 以上三种组成的数组。
1. ref定义的基本数据类型
<script lang="ts" setup name="Car">
import { ref, watch } from 'vue';
let sum = ref(0);
function addSum() {
sum.value++;
}
// 监听sum变化,当sum大于10时停止监听
// 这里watch中的sum不要加value,因为watch监视的是一个ref响应式对象,加了value就成了监视属性
// watch()返回一个停止函数,调用该函数可以停止监听
let stopWatch = watch(sum, (newVal, oldVal) => {
console.log('sum变化了', newVal, oldVal);
if (newVal > 10) {
stopWatch(); // 停止监听
}
})
</script>
<template>
<div class="class">
<h2>当前计数:{{ sum }}</h2>
<br/>
<button @click="addSum">sum+1</button>
</div>
</template>
<style scoped>
.class {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%; /* 使内容占满整个高度 */
color: rgb(214, 12, 12);
font-size: 20px;
}
button {
background-color: blue;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin-top: 10px;
}
</style>
2.ref定义的对象数据类型
<script lang="ts" setup name="Watch02">
import { ref, watch } from 'vue';
let person = ref({ name: '张三', age: 20 });
function changeName() { // 改变姓名
person.value.name = '李四'
}
function changeAge() { // 改变年龄
person.value.age ++;
}
function changePerson() { // 改变整个人
person.value = { name: '王五', age: 90}
}
// 监听person的变化,只有执行changePerson函数时才会触发,
// 因为changeName和changeAge函数不会改变person的地址,只改变了内部属性的值,所以不会触发
// watch(person, (newVal, oldVal) => { // 监听person的变化
// console.log('person 变化了', newVal, oldVal);
// });
// 深度监听person的变化,会监听到内部属性的变化
// changeName和changeAge函数也会触发
watch(person, (newVal, oldVal) => { // 监听person的变化
console.log('person 变化了', newVal, oldVal);
}, { deep: true });
</script>
<template>
<div class="class">
<h2>姓名:{{ person.name }}</h2>
<br/>
<h2>年龄:{{ person.age }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
</div>
</template>
<style scoped>
.class {
background-color: #f8f9fa; /* 背景颜色 */
padding: 20px; /* 内边距 */
border-radius: 10px; /* 圆角 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影 */
text-align: center; /* 文本居中 */
max-width: 500px; /* 最大宽度 */
margin: 0 auto; /* 水平居中 */
}
button {
background-color: blue;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 10px 10px 0 10px; /* 外边距 */
transition: background-color 0.3s ease; /* 按钮背景颜色过渡效果 */
}
</style>
3.reactivate 定义对象类型数据
监听reactive定义的 对象类型 数据,默认是开启深度监视的,且无法取消深度监视。
<script lang="ts" setup name="Watch03">
import { reactive, watch } from 'vue';
let person = reactive({ name: '张三', age: 20 });
function changeName() { // 改变姓名
person.name = '李四'
}
function changeAge() { // 改变年龄
person.age ++;
}
function changePerson() { // 改变整个人
Object.assign(person, { name: '王五', age: 90})
}
// 监听reactive定义的 对象类型 数据,默认是开启深度监视的,就算person变化了一点,都会触发回调函数
watch(person, (newVal, oldVal) => { // 监听person的变化
console.log('person 变化了', newVal, oldVal);
});
</script>
<template>
<div class="class">
<h2>姓名:{{ person.name }}</h2>
<br/>
<h2>年龄:{{ person.age }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
</div>
</template>
<style scoped>
.class {
background-color: #f8f9fa; /* 背景颜色 */
padding: 20px; /* 内边距 */
border-radius: 10px; /* 圆角 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影 */
text-align: center; /* 文本居中 */
max-width: 500px; /* 最大宽度 */
margin: 0 auto; /* 水平居中 */
}
button {
background-color: blue;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 10px 10px 0 10px; /* 外边距 */
transition: background-color 0.3s ease; /* 按钮背景颜色过渡效果 */
}
</style>
4. 监视ref或reactive定义的对象数据类型中的某个属性
<script lang="ts" setup name="Watch04">
import { reactive, watch } from 'vue';
let person = reactive({
name: '张三',
age: 20,
Car: {
name: '宝马',
color: '红色'
}
});
function changeName() {
person.name= '李四'
}
function changeAge() {
person.age += 1;
}
function changeCarName() {
person.Car.name = '奔驰';
}
function changeCarColor() {
person.Car.color = '蓝色';
}
function changeCar() {
person.Car= { name: '兰博基尼', color: '黑色' }
}
// 监听person中某个基本类型的值的变化,这里只监视person.name,
// 要写成一个getter函数,() => { return person.name },这里简写了
watch(() => person.name, (newVal, oldVal) => {
console.log('person changed', newVal, oldVal);
});
// 监听person中某个对象的值的变化,这里监视person.Car,
// 加上deep:true选项,可以监视对象内部值的变化(car.name, car.color)
// 不加deep:true选项,只监视car对象本身的变化
watch(() => person.Car, (newVal, oldVal) => {
console.log('person changed', newVal, oldVal);
}, { deep: true });
</script>
<template>
<div class="class">
<h2>姓名:{{ person.name }}</h2>
<br/>
<h2>年龄:{{ person.age }}</h2>
<br/>
<h2>车品牌:{{ person.Car.name }}</h2>
<br/>
<h2>车颜色:{{ person.Car.color }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeCarName">修改车品牌</button>
<button @click="changeCarColor">修改车颜色</button>
<button @click="changeCar">修改整辆车</button>
</div>
</template>
<style scoped>
.class {
background-color: #f8f9fa; /* 背景颜色 */
padding: 20px; /* 内边距 */
border-radius: 10px; /* 圆角 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影 */
text-align: center; /* 文本居中 */
max-width: 500px; /* 最大宽度 */
margin: 0 auto; /* 水平居中 */
}
button {
background-color: blue;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 10px 10px 0 10px; /* 外边距 */
transition: background-color 0.3s ease; /* 按钮背景颜色过渡效果 */
}
</style>
5.上述类型数组
<script lang="ts" setup name="Watch05">
import { reactive, watch } from 'vue';
let person = reactive({
name: '张三',
age: 20,
Car: {
name: '宝马',
color: '红色'
}
});
function changeName() {
person.name= '李四'
}
function changeAge() {
person.age += 1;
}
function changeCarName() {
person.Car.name = '奔驰';
}
function changeCarColor() {
person.Car.color = '蓝色';
}
function changeCar() {
person.Car= { name: '兰博基尼', color: '黑色' }
}
// 监听person的name和Car属性
watch([() => person.name, () => person.Car], (newVal, oldVal) => {
console.log('person changed', newVal, oldVal);
}, { deep: true });
</script>
<template>
<div class="class">
<h2>姓名:{{ person.name }}</h2>
<br/>
<h2>年龄:{{ person.age }}</h2>
<br/>
<h2>车品牌:{{ person.Car.name }}</h2>
<br/>
<h2>车颜色:{{ person.Car.color }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeCarName">修改车品牌</button>
<button @click="changeCarColor">修改车颜色</button>
<button @click="changeCar">修改整辆车</button>
</div>
</template>
<style scoped>
.class {
background-color: #f8f9fa; /* 背景颜色 */
padding: 20px; /* 内边距 */
border-radius: 10px; /* 圆角 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影 */
text-align: center; /* 文本居中 */
max-width: 500px; /* 最大宽度 */
margin: 0 auto; /* 水平居中 */
}
button {
background-color: blue;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 10px 10px 0 10px; /* 外边距 */
transition: background-color 0.3s ease; /* 按钮背景颜色过渡效果 */
}
</style>
WatchEffect
使用watch监视时需要传入需要监视的对象,当需要监视多个对象时就要先把这些对象先告诉watch,然后才能监视。但是当需要监视的对象太多时,需要将他们全部告诉watch,些许麻烦。watchEffect可以省略这一步,直接写对象变化后的处理。
<script lang="ts" setup name="WatchEffect">
import { ref, watchEffect } from 'vue';
let temp = ref(30)
let height = ref(10)
function changeHeight() {
height.value += 10
}
function changeTemp() {
temp.value += 10
}
// watchEffect 不需要传值,直接写监听对象处理函数
watchEffect(() => {
console.log('watchEffect', temp.value)
if (temp.value > 50) {
console.log('温度超过50度了,现在是', temp.value, '度')
}
})
</script>
<template>
<div class="class">
<h2>温度:{{ temp }}</h2>
<br/>
<h2>高度:{{ height }}</h2>
<br/>
<button @click="changeTemp">修改温度</button>
<button @click="changeHeight">修改高度</button>
</div>
</template>
<style scoped>
.class {
background-color: #f8f9fa; /* 背景颜色 */
padding: 20px; /* 内边距 */
border-radius: 10px; /* 圆角 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影 */
text-align: center; /* 文本居中 */
max-width: 500px; /* 最大宽度 */
margin: 0 auto; /* 水平居中 */
}
button {
background-color: blue;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 10px 10px 0 10px; /* 外边距 */
transition: background-color 0.3s ease; /* 按钮背景颜色过渡效果 */
}
</style>