watch监听
特别注意:凡是监视对象类型,只要引用没有发生变化,oldValue和newValue一致。
作用:监视数据的变化(和Vue2
中的watch
作用一致)
特点:Vue3
中的watch
只能监视以下四种数据:
ref
定义的数据。
reactive
定义的数据。
函数返回一个值(getter
函数)。
一个包含上述内容的数组。
我们在Vue3
中使用watch
的时候,通常会遇到以下几种情况:
情况一 监视ref
定义的【基本类型】数据
监视ref
定义的【基本类型】数据:直接写数据名即可,不用添加.value,监视的是其value
值的改变。
<template>
<div class="person">
<h2>监视ref定义的【基本类型】数据:直接写数据名即可,监视的是其value值的改变。</h2>
<h2>当前求和数据: {{sum}}</h2>
<button @click="changeSum">点我sum + 1</button>
</div>
</template>
<script setup lang="ts" name="Person">
import {ref, watch} from 'vue'
//数据
let sum = ref(0)
//方法
function changeSum() {
sum.value += 1;
}
//监视
const stopWatch = watch(sum, (newVlaue, oldValue) => { //参数说明:监视对象, 回调函数
console.log('sum变化了从' + oldValue + "变为了" + newVlaue);
if(sum.value >= 10) {
stopWatch() //返回的是一个停止监听的函数
}
})
</script>
<style>
.person {
background-color: skyblue;
box-shadow: 0 0 10px; /* 盒子阴影 */
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
情况二 监视ref
定义的【对象类型】数据
监视ref
定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。
注意:
若修改的是ref
定义的对象中的属性,newValue
和 oldValue
都是新值,因为它们是同一个对象。
若修改整个ref
定义的对象,newValue
是新值, oldValue
是旧值,因为不是同一个对象了。
<template>
<div class="person">
<h2>监视ref定义的【对象类型】数据</h2>
<h2>姓名: {{person.name}}</h2>
<h2>年龄: {{person.age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改人</button>
</div>
</template>
<script setup lang="ts" 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) => { //直接这样写,只会监视person这个对象的变化,对于其内部的变化不会触发
// console.log('person从: ', oldValue, "变为: ", newValue);
// });
//深度监视
watch(person, (newValue, oldValue) => { //需要传递第三个参数 {deep:true}
console.log('person从: ', oldValue, "变为: ", newValue);
}, {deep: true}); //### 还可以添加参数 {immediate:?} 这样初始化的时候也会监视一下
</script>
<style>
.person {
background-color: skyblue;
box-shadow: 0 0 10px; /* 盒子阴影 */
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
情况三 监视reactive
定义的【对象类型】数据
监视reactive
定义的【对象类型】数据,且默认开启了深度监视。
<template>
<div class="person">
<h2>监视reactive定义的【对象类型】数据,且默认开启了深度监视。</h2>
<h2>姓名: {{person.name}}</h2>
<h2>年龄: {{person.age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改人</button>
</div>
</template>
<script setup lang="ts" name="Person">
import {reactive, watch} from 'vue'
//数据
let person = reactive({
name: '张三',
age: 18
})
//方法
function changeName() {
person.name += "~";
}
function changeAge() {
person.age += 1;
}
function changePerson() {
// person = {name: '李四', age: 90}; //这里由于使用了reactive所以不能直接修改对象
//注意:这里这个引用没有发生变化哦
Object.assign(person, {name: '李四', age: 90}); //需要使用这种方式,响应式才不会被破坏
}
//监视 因为person是reactive定义的 默认深度监视,无法关闭
watch(person, (newValue, oldValue) => { //因为person是reactive定义的,直接这样写,默认就开启了deep监视
console.log('person从: ', oldValue, "变为: ", newValue);
});
</script>
<style>
.person {
background-color: skyblue;
box-shadow: 0 0 10px; /* 盒子阴影 */
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
情况四 监视ref
或reactive
定义的【对象类型】数据中的某个属性
监视ref
或reactive
定义的【对象类型】数据中的某个属性,注意点如下:
- 若该属性值不是【对象类型】,需要写成函数形式。
- 若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。
结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。
<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="changeOneCar">修改第一台车</button>
<button @click="changeTwoCar">修改第二台车</button>
<button @click="changeCar">修改整个车</button>
</div>
</template>
<script setup lang="ts" name="Person">
import {reactive, watch} from 'vue'
//数据
let person = reactive({
name: '张三',
age: 20,
car: {
c1: '小米',
c2: '奔驰'
}
})
//方法
function changeName() {
person.name += '~';
}
function changeAge() {
person.age += 1;
}
function changeOneCar() {
person.car.c1 += '~';
}
function changeTwoCar() {
person.car.c2 += '~';
}
function changeCar() {
Object.assign(person, {
name: '李四',
age: 30,
car: {
c1: '大众',
c2: '马自达'
}
})
}
//监听, 为了监视响应式对象中的某个对象,且该属性是:基本数据类型,要写为函数式
watch(() => person.name, (newValue, oldValue) => {
console.log('person.name变化了', newValue, oldValue);
})
//##### 监听对象中的对象 ######
// watch(person.car, (newValue, oldValue) => { //可以发现监视响应式对象中的对象属性ok的,但是修改整个外层对象时,又无法监听到
// console.log('person.car变化了', newValue, oldValue);
// })
// watch(() => person.car, (newValue, oldValue) => { //而使用函数式后 car整体变化ok了,但是细节变化又不行了,因为监听变化的是car变量的引用了
// console.log('person.car变化了', newValue, oldValue);
// })
//##### 所以得出如果想要 监听对象中的对象 细枝末节变和整体变都可以监听到的最佳实践 ######
watch(() => person.car, (newValue, oldValue) => {
console.log('person.car变化了 或者 car中的属性变化了', newValue, oldValue);
}, {deep: true})
// watch(() => person.car.c1, (newValue, oldValue) => {
// console.log('person.car.c1变化了', newValue, oldValue);
// })
</script>
<style>
.person {
background-color: skyblue;
box-shadow: 0 0 10px; /* 盒子阴影 */
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
监听对象中的对象最佳实践:
//##### 监听对象中的对象 ######
// watch(person.car, (newValue, oldValue) => { //可以发现监视响应式对象中的对象属性ok的,但是修改整个外层对象时,又无法监听到
// console.log('person.car变化了', newValue, oldValue);
// })
// watch(() => person.car, (newValue, oldValue) => { //而使用函数式后 car整体变化ok了,但是细节变化又不行了,因为监听变化的是car变量的引用了
// console.log('person.car变化了', newValue, oldValue);
// })
//##### 所以得出如果想要 监听对象中的对象 细枝末节变和整体变都可以监听到的最佳实践 ######
watch(() => person.car, (newValue, oldValue) => {
console.log('person.car变化了 或者 car中的属性变化了', newValue, oldValue);
}, {deep: true})
情况五 监视上诉的多个数据
监视上述的多个数据,即我们的watch使用时第一个参数可以传递一个数组,只要其中的一个发生变化都会执行回调函数。这里对应的写法都推荐函数式。说明:基本类型也可以使用函数式写法如:() => name.value
<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="changeOneCar">修改第一台车</button>
<button @click="changeTwoCar">修改第二台车</button>
<button @click="changeCar">修改整个车</button>
</div>
</template>
<script setup lang="ts" name="Person">
import {reactive, ref, watch} from 'vue'
//数据
let name = ref(0);
let person = reactive({
name: '张三',
age: 20,
car: {
c1: '小米',
c2: '奔驰'
}
});
//方法
function changeName() {
person.name += '~';
}
function changeAge() {
person.age += 1;
}
function changeOneCar() {
person.car.c1 += '~';
}
function changeTwoCar() {
person.car.c2 += '~';
}
function changeCar() {
Object.assign(person, {
name: '李四',
age: 30,
car: {
c1: '大众',
c2: '马自达'
}
})
}
//监听
watch([() => person.name, () => person.car.c1], (newValue, oldValue) => {
console.log('person.name变化了 或者 person.car.c1', newValue, oldValue);
}, {deep: true})
</script>
<style>
.person {
background-color: skyblue;
box-shadow: 0 0 10px; /* 盒子阴影 */
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
标签:car,watch,监听,person,oldValue,监视,newValue
From: https://www.cnblogs.com/fragmentary/p/18626669