赞
踩
侦听器watch是用来监视数据变化,并进行一些附加操作的。
watch可以侦听数据源类型有以下4种:
监视ref定义的基本类型的数据,实际是观察.value的变化。
<template>
<div class="person">
<h2>watch-ref</h2>
<h3>A:<input type="text" v-model="a" /></h3>
<h2>{{ a }}</h2>
</div>
</template>
<script lang='ts' setup name="Computed">
import { computed, ref, watch } from 'vue'
let a = ref(1)
// 监视sum的变化, 返回值是一个停止监听函数
let stopWatch = watch(a, (newVal, oldVal) => {
if(newVal >= 100){
stopWatch()
}
console.log('newVal: ', newVal);
console.log('oldVal: ', oldVal);
})
</script>
页面效果如下:
从图上可以看出:
1、成功监听了a.value的变化
2、监听返回一个函数,是停止函数,可以在特定条件下,调用其来停止监听。stopWatch的输出如下图,其功能性显而易见。
监听对象时,监听的是对象地址的变化,如果只是对象属性值的变化,则不会被监听。
<template>
<div class="person">
<h2>watch-ref-obj</h2>
<h3>姓名:{{ person.name }}</h3>
<h3>年龄:{{ person.age }}</h3>
<button @click="updatePersonAge">修改age</button>
<button @click="updatePerson">修改整个Person</button>
</div>
</template>
<script lang='ts' setup name="Computed">
import { ref, watch } from 'vue'
let person = ref(
{
name: "李四",
age: 99
}
)
function updatePersonAge() {
person.value.age += 1
}
function updatePerson() {
person.value = {name: '王五', age: 100}
}
// 监视person的变化, 返回值是一个停止监听函数,监听的是对象地址的变化,如果只是属性值变化,则不会被监听。
let stopWatch = watch(person, (newVal, oldVal) => {
console.log('newVal: ', newVal);
console.log('oldVal: ', oldVal);
})
</script>
页面效果如下:
从图上可以看出:
1、修改单个属性值的时候,是没有被监听的
2、修改整个对象时,是监听了的。因为对象地址发生了变化。
// 如果要监视对象内部属性值的变化,则需要配置deep为true,当然这种设置在地址值发生变化的时候也是会监听的。
// 但只改对象属性的时候,新旧值是一样的,都是新值
let stopWatch = watch(person, (newVal, oldVal) => {
console.log('newVal: ', newVal);
console.log('oldVal: ', oldVal);
}, {deep: true})
页面效果如下:
★ 从上述动图可以看到,只是改age的时候,新旧的值是完全一样的,且都是新值,这是为什么呢?是因为这里改的是对象里属性的值,并没有改对象本身的地址。
监听reactive的响应式对象时,默认是开启{deep: true}
的。且设置为false的时候是不生效的。
<template>
<div class="person">
<h2>watch-ref-obj</h2>
<h3>姓名:{{ person.name }}</h3>
<h3>年龄:{{ person.age }}</h3>
<button @click="updatePersonAge">修改age</button>
<button @click="updatePerson">修改整个Person</button>
</div>
</template>
<script lang='ts' setup name="Computed">
import { reactive, watch } from 'vue'
let person = reactive(
{
name: "李四",
age: 99
}
)
function updatePersonAge() {
person.age += 1
}
function updatePerson() {
Object.assign(person, {name: '王五', age: 100})
}
// 监视person的变化, 监听reactive的响应式对象时,默认是开启`{deep: true}`的。
// let stopWatch = watch(person, (newVal, oldVal) => {
// console.log('newVal: ', newVal);
// console.log('oldVal: ', oldVal);
// })
// 配置deep为true和不配置是一样的效果
let stopWatch = watch(person, (newVal, oldVal) => {
console.log('newVal: ', newVal);
console.log('oldVal: ', oldVal);
}, {deep: true})
</script>
页面效果如下:
★ 从上述动图可以看到,改age的时候,新旧的值是完全一样的,且都是新值,这是为什么呢?是因为这里改的是对象里属性的值,并没有改对象本身的地址。
★ 从上述动图可以看到,改整个对象的时候,新旧的值是完全一样的,且都是新值,这是为什么呢?是因为这里Object.assign()
方法改的也是对象里属性的值类似于一个一个set值,也没有改对象本身的地址。
监听对象为() => {return person.bmi}
是一个有返回值的函数
<template>
<div class="person">
<h2>watch-getter</h2>
<h3>姓名:{{ person.name }}</h3>
<h3>年龄:{{ person.age }}</h3>
<h3>身高:{{ person.bmi.high }}</h3>
<h3>体重:{{ person.bmi.weight }}</h3>
<button @click="updatePersonName">修改name</button>
<button @click="updatePersonAge">修改age</button>
<button @click="updateBmiHigh">修改身高</button>
<button @click="updateBmi">修改bmi</button>
</div>
</template>
<script lang='ts' setup name="Computed">
import { reactive, watch } from 'vue'
let person = reactive(
{
name: "李四",
age: 99,
bmi:{
high: 173,
weight: 82
}
}
)
function updatePersonName() {
person.name += '@'
}
function updatePersonAge() {
person.age += 1
}
function updateBmiHigh() {
person.bmi.high += 1
}
function updateBmi() {
person.bmi = {high: 190, weight: 70}
}
// 只监听对象的一个属性,该属性是基础类型
watch(() => {return person.age}, (newVal, oldVal) => {
console.log('newVal: ', newVal);
console.log('oldVal: ', oldVal);
})
// 只监听对象的一个属性,但该属性是对象类型
let stopWatch = watch(() => {return person.bmi}, (newVal, oldVal) => {
console.log('newVal: ', newVal);
console.log('oldVal: ', oldVal);
}, {deep:true})
</script>
页面效果如下:
由上图可以看出:
1、单独监听age的时候,修改name是没有输出的;
2、监听bmi的时候 ,单独修改身高,和修改整个bmi都是有被监听,有输出的
此外,如果监听的是对象的属性A是对象类型,那么如果需要在修改整个对象A和修改对象A下的某个属性都监听变化的话,这需要加上{deep:true}
的配置才行。
示例:监听人的age和身高
<template>
<div class="person">
<h2>watch-arr[响应式数据列表]</h2>
<h3>姓名:{{ person.name }}</h3>
<h3>年龄:{{ person.age }}</h3>
<h3>身高:{{ person.bmi.high }}</h3>
<h3>体重:{{ person.bmi.weight }}</h3>
<button @click="updatePersonName">修改name</button>
<button @click="updatePersonAge">修改age</button>
<button @click="updateBmiHigh">修改身高</button>
<button @click="updateBmi">修改bmi</button>
</div>
</template>
<script lang='ts' setup name="Computed">
import { reactive, watch } from 'vue'
let person = reactive(
{
name: "李四",
age: 99,
bmi:{
high: 173,
weight: 82
}
}
)
function updatePersonName() {
person.name += '@'
}
function updatePersonAge() {
person.age += 1
}
function updateBmiHigh() {
person.bmi.high += 1
}
function updateBmi() {
person.bmi = {high: 190, weight: 70}
}
// 监视多个数据源组成的数组 [() => {return person.age}, () => {return person.bmi.high}]
let stopWatch = watch([() => {return person.age}, () => {return person.bmi.high}], (newVal, oldVal) => {
console.log('newVal: ', newVal);
console.log('oldVal: ', oldVal);
})
</script>
页面效果如下:
由上图可以看到:
1、成功的监听了age和high
2、newVal和oldVal都是数组形式,索引顺序和监听顺序保持一致。
使用watchEffect监听数据,会立即运行一个函数,同时监听响应式数据,并在数据更改时重新执行该函数。
示例如下:
<template>
<div class="person">
<h2>watch-watchEffect</h2>
<h3>姓名:{{ person.name }}</h3>
<h3>年龄:{{ person.age }}</h3>
<h3>身高:{{ person.bmi.high }}</h3>
<h3>体重:{{ person.bmi.weight }}</h3>
<button @click="updatePersonAge">修改age</button>
<button @click="updateBmiHigh">修改身高</button>
</div>
</template>
<script lang='ts' setup name="Computed">
import { reactive, watch, watchEffect } from 'vue'
let person = reactive(
{
name: "李四",
age: 99,
bmi:{
high: 173,
weight: 82
}
}
)
function updatePersonAge() {
person.age += 1
}
function updateBmiHigh() {
person.bmi.high += 1
}
// watchEffect实现
watchEffect(()=>{
// 身高大于178,或者,年龄大于102的时候提示
if(person.age > 102 || person.bmi.high > 178){
console.log('身高大于178,或者,年龄大于102了');
// to do something
}
})
// watch实现
watch([() => person.age, () => person.bmi.high], (newVal) => {
// 身高大于178,或者,年龄大于102的时候提示
let [newAge, newHigh] = newVal
if (newAge > 102 || newHigh > 178) {
console.log('身高大于178,或者,年龄大于102了');
// to do something
}
})
</script>
页面效果如下:
从上述示例中 watchEffect实现
和 watch实现
实现同一个功能的代码中,就可以看到二者的区别。从而根据实际场景进行选择使用。
项目 | watch | watchEffect |
---|---|---|
是否具有监听数据变化的功能 | 是 | 是 |
是否需要指明监听对象 | 是(指哪儿打哪儿) | 否(打哪儿指哪儿) |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。