vue3.0(八) 监听器(watch),高级监听器(watchEffect)

文章目录

  • watch
    • 1 watch的用法
    • 2 watch的高级用法
    • 3 watch性能优化
  • watchEffect
    • 1 停止监听
    • 2 侦听多个状态
    • 3 懒执行
  • watch和watchEffect的区别
  • watch和computed的区别


watch

watch特性进行了一些改变和优化。与computed不同,watch通常用于监听数据的变化,并执行一些副作用,侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。

1 watch的用法

  1. watch的基本用法
    watch(source, callback, options?)
    

    source表示要监听的数据,可以是一个响应式的数据对象、一个计算属性或一个方法的返回值;callback表示当数据发生变化时要执行的回调函数;options表示watch的一些配置选项,例如immediate、deep、flush等。

  2. 监听 ref 定义的响应式数据
    <template><div><div>值:{{count}}</div><button @click="add">改变值</button></div>
    </template><script>
    import { ref, watch } from 'vue'
    export default {setup () {const count = ref(0)const add = () => {count.value++}watch(count, (newVal, oldVal) => {console.log('值改变了', newVal, oldVal)})return {count,add}}
    }
    </script>
    
    上述代码执行效果
  3. 监听 reactive 定义的响应式数据
    <template><div><div>姓名:{{ obj.name }}</div><div>年龄:{{ obj.age }}</div><button @click="changeName">改变值</button></div>
    </template><script>
    import { reactive, watch } from 'vue'
    export default {setup () {const obj = reactive({name: 'zs',age: 14})const changeName = () => {obj.name = 'ls'}watch(obj, (newVal, oldVal) => {console.log('值改变了', newVal, oldVal)})return {obj,changeName}}
    }
    </script>
    

上述代码执行结果
注:此处监听的新值和旧值相同,主要是因为新旧值引用地址是相同的,
此处可采取computed计算属性先实现深拷贝。

	<template><div><div>姓名:{{ obj.name }}</div><div>年龄:{{ obj.age }}</div><button @click="changeName">改变值</button></div></template><script>import { reactive, watch, computed } from 'vue'export default {setup () {const obj = reactive({name: 'zs',age: 14})const changeName = () => {obj.name = 'ls'}const deepObj = computed(() => {return JSON.parse(JSON.stringify(obj))})watch(deepObj, (newVal, oldVal) => {console.log('值改变了', newVal, oldVal)})return {obj,changeName}}}</script>
  1. 监听多个ref的值,采用数组形式
    <template><div><!-- 侦听多个变量 -->姓名:<input v-model="userName" type="text">年龄:<input v-model="age" type="number"></div>
    </template>
    <script lang="ts">
    import { defineComponent, ref, watch } from 'vue'
    export default defineComponent({setup () {const userName = ref<string>('张三')const age = ref<number>(18)watch([userName, age], (newVal, oldVal) => {console.log(newVal, oldVal)})return {userName,age}}
    })
    </script>
    

在这里插入图片描述

  1. 监听reactive对象中某个属性的变化
    <template><div><div>{{obj.name}}</div><div>{{obj.age}}</div><button @click="changeName">改变值</button></div>
    </template><script>
    import { reactive, watch } from 'vue'
    export default {setup () {const obj = reactive({name: 'zs',age: 14})const changeName = () => {obj.age++}watch(() => obj.age, (newVal, oldVal) => {console.log(newVal, oldVal)})return {obj,changeName}}
    }
    </script>
    

在这里插入图片描述

2 watch的高级用法

  1. 一次性监听
    每当被侦听源发生变化时,侦听器的回调就会执行。如果希望回调只在源变化时触发一次,请使用 once: true 选项。
    <template><div><div>{{obj.name}}</div><div>{{obj.classInfo.studentNum}}</div><button @click="changeName">改变值</button></div>
    </template><script>
    import { reactive, watch } from 'vue'
    export default {setup () {const obj = reactive({name: 'zs',age: 14,classInfo: {className: '一年级',studentNum: 45}})const changeName = () => {obj.classInfo.studentNum++}watch(() => obj, (newVal, oldVal) => {console.log(newVal, oldVal)}, {once: true})return {obj,changeName}}
    }
    </script>
    
  2. 深层侦听器
    直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发:deep 选项,强制转成深层侦听器:
    <template><div><div>{{obj.name}}</div><div>{{obj.classInfo.studentNum}}</div><button @click="changeName">改变值</button></div>
    </template><script>
    import { reactive, watch } from 'vue'
    export default {setup () {const obj = reactive({name: 'zs',age: 14,classInfo: {className: '一年级',studentNum: 45}})const changeName = () => {obj.classInfo.studentNum++}watch(() => obj, (newVal, oldVal) => {console.log(newVal, oldVal)}, {deep: true // 不添加deep属性,watch不会触发})return {obj,changeName}}
    }
    </script>
    

    注意:当我们使用deep选项时,watch的性能会受到一定的影响,因为Vue需要对对象或数组进行递归遍历。因此,只有在必要的情况下才应该使用deep选项

  3. 即时回调的侦听器
    watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。通过传入 immediate: true 选项来强制侦听器的回调立即执行:
    import { reactive, watch } from 'vue'
    const state = reactive({count: 2
    })
    watch(() => state.count,(newVal, oldVal) => {console.log(newVal, oldVal)},{ immediate: true }
    )
    
  4. flush 回调的触发时机
  • sync:同步模式下执行
  • pre:在数据变化之前执行回调函数
  • post:在数据变化之后执行回调函数,但是需要等待所有依赖项都更新后才执行
    import { reactive, watch } from 'vue'
    const state = reactive({count: 2
    })
    watch(() => state.count,(newVal, oldVal) => {console.log(newVal, oldVal)},{ flush: sync }
    )
    

3 watch性能优化

  1. 使用computed代替watch
    import { reactive, computed } from 'vue'
    const state = reactive({count: 2
    })const doubleCount = computed(() => {return state.count * 2
    })
    console.log(doubleCount.value) // 输出:2
    state.count++
    console.log(doubleCount.value) // 输出:4
    
  2. 使用throttle和debounce控制回调函数的执行频率
    频繁地监听一个值的变化,并在变化时执行一些操作。如果回调函数执行的太频繁,会影响性能。为了避免这种情况,我们可以使用throttle和debounce控制回调函数的执行频率
    throttle可以用于控制函数在一定时间内只能执行一次,
    debounce可以用于控制函数在一定时间内不会连续执行
    import { reactive, watch } from 'vue'
    import { throttle } from 'lodash-es'
    const state = reactive({count: 3
    })
    watch(() => state.count,throttle((newVal, oldVal) => {console.log(newVal, oldVal)}, 1000)
    )
    state.count++
    

watchEffect

watchEffect 函数来创建高级侦听器。与 watch 和 computed 不同,
watchEffect 不需要指定依赖项,自动追踪响应式状态的变化,并在变化时重新运行

<template><div><div>{{obj.name}}</div><div>{{obj.age}}</div><button @click="changeAge">改变值</button></div>
</template>
<script>
import { reactive, watch, watchEffect } from 'vue'
export default {setup () {const obj = reactive({name: 'zs',age: 14,})const changeName = () => {obj.age++}watchEffect(() => {console.log(obj.age)})return {obj,changeAge}}
}
</script>

1 停止监听

watchEffect 函数不会返回一个停止侦听的函数。如果我们需要停止侦听,我们可以将 watchEffect 的返回值设为 null

const stop = watchEffect(() => {})// 当不再需要此侦听器时:
stop()

2 侦听多个状态

如果需要侦听多个响应式状态,可以在 watchEffect 函数中使用这些状态,并在函数中返回一个计算值,

<script>
import { reactive, watchEffect } from 'vue'
export default {setup () {const state = reactive({count1: 2,count2: 3})watchEffect(() => {const sum = state.count1 + state.count2console.log(sum)})// 改变状态,输出  5state.count1++// 改变状态,输出 8state.count2 += 2return {}}
}
</script>

3 懒执行

watchEffect 函数也支持懒执行(lazy evaluation)。如果我们将 watchEffect 的第二个参数设置为 { lazy: true },则这个函数会在第一次访问响应式状态时才会被运行

const state = reactive({count: 2})watchEffect(() => {console.log(state.count)}, { lazy: true })// 改变状态,输出  2 3state.count++

watch和watchEffect的区别

watch 和 watchEffect 都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:
watch 监听函数可以添加配置项,也可以配置为空,配置项为空的情况下,
watch的特点为:

  • 有惰性:运行的时候,不会立即执行;
  • 更加具体:需要添加监听的属性;
  • 可访问属性之前的值:回调函数内会返回最新值和修改之前的值;
  • 可配置:配置项可补充 watch 特点上的不足:
  • immediate:配置 watch 属性是否立即执行,值为 true 时,一旦运行就会立即执行,值为 false时,保持惰性。
  • deep:配置 watch 是否深度监听,值为 true 时,可以监听对象所有属性,值为 false 时保持更加具体特性,必须指定到具体的属性上。
    watchEffect 特点
  • 非惰性:一旦运行就会立即执行;
  • 更加抽象:使用时不需要具体指定监听的谁,回调函数内直接使用就可以;
  • 不可访问之前的值:只能访问当前最新的值,访问不到修改之前的值;

watch和computed的区别

computed(计算属性):

  1. 定义:computed是一个基于其依赖的数据进行计算的值,可以缓存计算的结果。
  2. 工作原理:Vue会自动追踪computed属性方法对data的数据依赖,并在依赖数据发生变化时重新计算computed属性的值。
    computed特点:
    • 支持缓存,只有依赖数据发生改变时才会重新进行计算。
    • 不支持异步操作,如果computed内有异步操作,则无效。
    • 必须通过return返回一个值。
    • 适合当一个属性受多个属性影响时使用。
    • 在模板中可以直接使用,访问时不需要加括号。
      watch(监听):
  3. 定义:watch用于监听响应式数据的变化,并在数据发生变化时执行一些自定义的操作。
  4. 工作原理:当监听的数据发生变化时,会直接触发相应的操作。
    watch特点:
    • 不支持缓存功能,监听的数据发生变化时会直接触发相应的操作。
    • 支持异步操作,适合监听路由和设置计时器等。
    • 可以没有返回值。
    • 适合当一条数据影响多条数据时使用。
    • 在模板中不能直接使用,需要通过事件或方法进行调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/696125.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】详解栈且实现

一.栈 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#xff1a;…

《Mybatis》系列文章目录

什么是 MyBatis&#xff1f; MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff…

动手学深度学习18 预测房价竞赛总结

动手学深度学习18 预测房价竞赛总结 李沐老师代码AutoGluonh2o集成学习automlQA 视频&#xff1a; https://www.bilibili.com/video/BV15Q4y1o7vc/?vd_sourceeb04c9a33e87ceba9c9a2e5f09752ef8 代码&#xff1a; https://www.bilibili.com/video/BV1rh411m7Hb/?vd_sourceeb04…

【强训笔记】day21

NO.1 思路&#xff1a;第一个位置放最小的&#xff0c;其次放最大的&#xff0c;依次类推。 代码实现&#xff1a; #include<iostream>using namespace std; int n;int main() {cin>>n;int left1,rightn;while(left<right){cout<<left<<" &…

华中科大:感谢大家,我的春招之旅结束了

今天在论坛上看到一个帖子&#xff0c;一位华中科大的同学&#xff0c;因为家中父亲突然病倒&#xff0c;发求助帖&#xff1a; 请问大家&#xff0c;春招走哪个方向能最快找到工作&#xff1f;还是说继续读研呢&#xff0c;但是家里急需钱…… 当时这个帖子直接热榜第一&…

数据可视化训练第6天(美国人口调查获得关于收入与教育背景的数据,并且可视化)

数据来源 https://archive.ics.uci.edu/dataset/2/adult 过程 首先&#xff1b;关于教育背景的部分翻译有问题。 本次使用字典嵌套记录数据&#xff0c;并且通过lambda在sorted内部进行对某个字典的排序&#xff0c;最后用plotly进行绘图 本次提取数据的时候&#xff0c;用到…

黑盒测试中的边界值分析

黑盒测试是一种基于需求和规格的测试方法&#xff0c;它主要关注软件系统输出的正确性和完整性&#xff0c;而不考虑内部代码的实现方式。在黑盒测试中&#xff0c;边界值分析是一种重要的测试技术&#xff0c;它可以帮助测试人员有效地发现输入和输出的问题。本文将从什么是边…

栈与递归的实现

1. 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则&#x…

【JavaScript超详细的学习笔记-上】JavaScrip超详细的学习笔记,共27部分,12多万字

想要获取笔记的可以点击下面链接获取 JavaScript超详细的学习笔记&#xff0c;点击我获取 一&#xff0c;JavaScript详细笔记 1&#xff0c;基础知识 1-1 基础知识 // 1&#xff0c;标识符命名规则&#xff1a;第一个字母必须是字母&#xff0c;下划线或一个美元符号。不能…

若依生成树表和下拉框选择树表结构(在其他页面使用该下拉框输入)

1.数据库表设计 生成树结构的主要列是id列和parent_id列&#xff0c;后者指向他的父级 2.来到前端代码生成器页面 导入你刚刚写出该格式的数据库表 3.点击编辑&#xff0c;来到字段 祖籍列表是为了好找到直接父类&#xff0c;不属于代码生成器方法&#xff0c;需要后台编…

实训一:设计系统主页作业

1.题目 设计系统主页。 2.目的 (1)熟悉Web前端项目开发环境。 (2)掌握如何建立Web前端项目&#xff0c;学会规划项目结构。 (3)掌握动态生成页面内容的方法。 (4)理解如何使用Flash显示图片新闻。 (5)会在应用系统中编写播放动态新闻的程序。 3.内容 建立项目结构&#xff0c;并…

ROS 2边学边练(47)-- 利用Xacro精简代码

前言 Xacro&#xff08;XML Macro&#xff09;是ROS&#xff08;Robot Operating System&#xff09;中用于处理URDF&#xff08;Unified Robot Description Format&#xff09;文件的一个宏处理工具。它允许你在URDF文件中定义和使用宏&#xff0c;这样可以减少重复的代码&…