当前位置:   article > 正文

Vue3快速上手(十)数据变化监视之侦听器watch和watchEffect_vue3实时监听数据变化

vue3实时监听数据变化

在这里插入图片描述

一、watch介绍

侦听器watch是用来监视数据变化,并进行一些附加操作的。
watch可以侦听数据源类型​有以下4种:

  1. 一个 ref定义的数据 (包括计算属性)
  2. 一个响应式对象数据(ref类,reactive类)
  3. 一个 getter 函数(有1个返回值的函数)
  4. 多个数据源组成的数组

二、监视ref定义的数据

监视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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

页面效果如下:
在这里插入图片描述
从图上可以看出:
1、成功监听了a.value的变化
2、监听返回一个函数,是停止函数,可以在特定条件下,调用其来停止监听。stopWatch的输出如下图,其功能性显而易见。
在这里插入图片描述

三、监视ref定义的响应式对象类型数据

3.1 监听对象整体的变化

监听对象时,监听的是对象地址的变化,如果只是对象属性值的变化,则不会被监听。

<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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

页面效果如下:

在这里插入图片描述
从图上可以看出:
1、修改单个属性值的时候,是没有被监听的
2、修改整个对象时,是监听了的。因为对象地址发生了变化。

3.2 监听对象内部属性值的变化

// 如果要监视对象内部属性值的变化,则需要配置deep为true,当然这种设置在地址值发生变化的时候也是会监听的。
// 但只改对象属性的时候,新旧值是一样的,都是新值

let stopWatch = watch(person, (newVal, oldVal) => {
    console.log('newVal: ', newVal);
    console.log('oldVal: ', oldVal);
}, {deep: true})
  • 1
  • 2
  • 3
  • 4

页面效果如下:
在这里插入图片描述
★ 从上述动图可以看到,只是改age的时候,新旧的值是完全一样的,且都是新值,这是为什么呢?是因为这里改的是对象里属性的值,并没有改对象本身的地址。

四、监视reactive定义的响应式对象类型数据

监听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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

页面效果如下:
在这里插入图片描述
★ 从上述动图可以看到,改age的时候,新旧的值是完全一样的,且都是新值,这是为什么呢?是因为这里改的是对象里属性的值,并没有改对象本身的地址。
★ 从上述动图可以看到,改整个对象的时候,新旧的值是完全一样的,且都是新值,这是为什么呢?是因为这里Object.assign()方法改的也是对象里属性的值类似于一个一个set值,也没有改对象本身的地址。

五、监视一个 getter 函数(有1个返回值的函数)

监听对象为() => {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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

页面效果如下:
在这里插入图片描述
由上图可以看出:
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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

页面效果如下:
在这里插入图片描述
由上图可以看到:
1、成功的监听了age和high
2、newVal和oldVal都是数组形式,索引顺序和监听顺序保持一致。

七、watchEffect以及和watch的区别

7.1 watchEffect

使用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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

页面效果如下:
在这里插入图片描述
从上述示例中 watchEffect实现 watch实现实现同一个功能的代码中,就可以看到二者的区别。从而根据实际场景进行选择使用。

7.2 watchEffect和watch的对比

项目watchwatchEffect
是否具有监听数据变化的功能
是否需要指明监听对象是(指哪儿打哪儿)否(打哪儿指哪儿)

END

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/492557
推荐阅读
相关标签
  

闽ICP备14008679号