Vue3全家桶 - Vue3 - 【4】侦听器

侦听器

一、 组合式API:

1.1 watch()函数

  • 创建侦听器:
    • 语法:
      // 先导入 watch 函数
      import { watch } from 'vue'
      watch(source, callback, options)
      
      • source
        • 需要侦听的数据源,可以是 ref(包括计算属性)、一个响应式对象、一个getter函数(获取对象属性的函数)、或多个数据源组成的数组
          • 🔺 注意
            • 第一个参数如果是 ref 声明的,不需要添加 .valuewatch会自动读取;
          • 和选项式API的区别:
            • 选项式API此处是个字符串;
            • 组合式API此处是个变量 / 数组 / 函数(要侦听的数据源);
      • callback
        • 回调函数;
        • 侦听单个数据源
          • 第一个参数 为 新值;
          • 第二个参数 为 旧值;
        • 侦听多个数据源组成的数组
          • 第一个参数数组新值
          • 第二个参数数组旧值
      • optinos
        • 配置项;
        • deep: true
          • 深度侦听,一般用在侦听的是getter函数返回的对象;
        • immediate: true
          • 创建好侦听器立即执行一遍;
        • flush: 'post'
          • 更改回调的执行机制(DOM更新后再执行);
  • 停止侦听器
    • 调用watch()返回的函数 即可 停止对该数据源的侦听
  • 总结
    • 侦听原始数据类型
      • 原始数据类型可以直接侦听;
      • 侦听的如果是对象的某个属性watch()的第一个参数必须是getter函数(一个箭头函数,返回值是要侦听的对象属性);
    • 侦听对象类型
      • 不开启深度侦听:
        • watch()第一个参数就是要侦听的数据,如果想改变某个属性值,可以触发回调,但是新旧值一样;
        • watch()第一个参数是个getter(),如果改变某个属性,默认情况下不会触发回调;
      • 开启深度侦听 + getter()
        • 对象的某个属性值改变,会触发回调,但是新旧值一样;
      • 🔺 watch()不管第一个参数是啥,对整个对象重新赋值,都是侦听不到的;
    • 侦听由多个响应式数据组成的数组
      • 数组里面有基本数据类型 / 对象的某个属性,可以触发回调,新旧值不一样;
      • 有对象,某个属性发生改变,新旧值一样;
  • 示例展示:
    • 侦听原始数据类型
      <script setup>import { ref, reactive, watch } from 'vue';let str = ref('禁止摆烂-才浅')let stopStrWatch = nullconst info = reactive({name: '才浅',age: 22})let stopInfoWatch = null// TODO 侦听原始数据类型的数据// NOTE stopStrWatch - watch 函数的返回值,调用该函数可以停止侦听器stopStrWatch = watch(str, (newVal, oldVal) => {console.log('str')console.log(newVal, oldVal)})// TODO 侦听对象的某个属性 - 需要提供 getter 函数(返回对象属性的函数)// NOTE stopInfoWatch - watch 函数的返回值,调用该函数可以停止侦听器stopInfoWatch = watch(() => info.age,(newVal, oldVal) => {console.log('info.age')console.log(newVal, oldVal)});
      </script><template><h4>str</h4><input type="text" v-model.trim="str"><hr><br><h4>info.age</h4><input type="text" v-model.number.trim="info.age">
      </template>
      
      • 效果展示:
        image.png
    • 侦听对象类型的数据:
      <script setup>import { ref, reactive, watch } from 'vue';let info = reactive({name: '才浅',age: 22})let likes = reactive({music: '听音乐',anime: '看动漫'})let anime = reactive({one: '完美世界',two: '不良人'})// TODO 侦听对象// NOTE 改变数据源的某个属性,可以触发回调,但是 newVal === oldVal => truewatch(info,(newVal, oldVal) => {console.log(newVal === oldVal)})// TODO 侦听对象 - getter函数(获取对象 / 对象的某个属性的函数)// NOTE 如果改变某个属性值,默认情况下回调不会触发watch(() => likes,(newVal, oldVal) => {console.log(newVal, oldVal)})// TODO 侦听对象 - getter函数 + 配置项// NOTE 如果嵌套属性值发生变化,并且配置了深度侦听,会触发回调,但 newVal === oldValwatch(() => anime,(newVal, oldVal) => {console.log(newVal, oldVal)},{// NOTE 开启深度侦听deep: true})
      </script><template><h4>info.age</h4><input type="text" v-model.number.trim="info.age"><hr><br><h4>likes.anime</h4><input type="text" v-model.trim="likes.anime"><hr><br><h4>anime.one</h4><input type="text" v-model.trim="anime.one"><hr><br>
      </template>
      
      • 效果展示:
        image.png
    • 侦听多个数据源组成的数组
      <script setup>import { ref, reactive, onMounted, watch } from 'vue';let str = ref('禁止摆烂-才浅')let likes = reactive({music: '听音乐',anime: '看动漫'})let anime = reactive({one: '完美世界',two: '不良人'})// TODO 侦听多个数据源组成的数组// NOTE 都能触发回调// NOTE 侦听:基本数据类型 - 发生改变,新旧值不一样// NOTE 侦听:对象的某个属性 - 发生改变,新旧值不一样// NOTE 侦听:对象数据类型 - 某个属性发生改变,新旧值一样watch([str, () => likes.anime, anime],([newStr, newLikesAnime, newAnime], [oldStr, oldLikesAnime, oldAnime]) => {console.log([newStr, newLikesAnime, newAnime], [oldStr, oldLikesAnime, oldAnime])}// (newVal, oldVal) => {//   console.log(newVal, oldVal)// }// 两种写法打印的数据都一样)
      </script><template><h4>侦听 - str</h4><input type="text" v-model="str"><hr><br><h4>侦听 - likes.anime</h4><input type="text" v-model="likes.anime"><hr><br><h4>侦听 - anime</h4><input type="text" v-model="anime.one">
      </template>
      
      • 效果展示:
        image.png

1.2 watchEffect()函数

  • watchEffect()会立即执行一遍回调函数,如果这时函数产生了副作用,Vue会自动追踪副作用的依赖关系,自动分析出响应源;
  • 语法
    import { watchEffect } from 'vue'
    watchEffect(() => {}, {})
    
  • 示例展示:
    <script setup>// 引入 watch 函数import { reactive, ref, watchEffect } from 'vue'// 账号let account = ref('Abc')// 员工let emp = reactive({name: 'Jack',salary: 7000})// 创建成功后立即执行一遍watchEffect(() => {// 此处用到了数据源,如果该数据源的值发生了变化,会重新执行该回调函数console.log('账号:' + account.value)console.log('员工的薪资:' + emp.salary)})
    </script><template>账号:<input type="text" v-model="account"><hr>员工薪资:<input type="number" v-model="emp.salary">
    </template>
    
  • 回调的触发时机
    • 默认情况下,用户创建的侦听器回调,都会在Vue组件更新之前 被调用,这意味着你在侦听器回调中访问的DOM将是被Vue更新之前的状态
    • 如果想在侦听器回调中能访问到被Vue更新之后的DOM,就需要指明flush: 'post'选项,或者你也可以使用更方便的别名 watchPostEffect()函数;
    • 示例展示:
      <script setup>import { onMounted, reactive, ref, watchEffect, watchPostEffect } from 'vue'// 账号let account = ref('Abc')// 密码let password = ref('123456')// 员工let emp = reactive({name: 'Jack',salary: 7000})// 当视图渲染成功后onMounted(() => {// 侦听账号watchEffect(() => {console.log('-------------------------------------')console.log('账号:' + account.value)// 默认情况下,回调触发机制:在 Dom 更新之前console.log(document.getElementById('titleAccount').innerHTML)})// 侦听密码watchEffect(() => {console.log('=====================================')console.log('密码:' + password.value)// 默认情况下,回调函数触发机制:在 Dom 更新之前console.log(document.getElementById('titlePassword').innerHTML)},// 更改回调函数触发机制:在 Dom 更新之后{ flush: 'post' })// 侦听薪资watchPostEffect(() => {console.log('=====================================')console.log('员工薪资:' + emp.salary)// 回调函数的触发机制:在 Dom 更新之后console.log(document.getElementById('titleSalary').innerHTML)})})
      </script><template><h1 id="titleAccount">账号:<i>{{ account }}</i></h1>账号:<input type="text" v-model="account"><hr><h1 id="titlePassword">密码:<i>{{ password }}</i></h1>密码:<input type="text" v-model="password"><hr><h1 id="titleSalary">员工薪资:<i>{{ emp.salary }}</i></h1>员工薪资:<input type="number" v-model="emp.salary">
      </template>
      
      • 效果展示:
        image.png
  • 停止侦听器
    • 要手动停止一个侦听器,请调用watchEffect()watchPostEffect()返回的函数;

二、 选项式API

  • 在 选项式API 中,我们可以使用 watch选项 在每次响应式属性发生变化时触发一个函数;

2.1 函数式侦听器

  • watch 选项中声明的函数即为函数式侦听器,其中函数名就是要侦听的数据源,函数中的参数1新值参数2旧值
    export default {watch: {侦听的数据(newVal, oldVal) {// 相关逻辑},// 侦听对象的某个属性'对象.属性'(newVal, oldVal) {// 相关逻辑}}
    }
    
  • 示例展示:
    <script>export default {data: () => ({str: '禁止摆烂-才浅',info: {name: '才浅',age: 22}}),// TODO 函数侦听器 - 侦听引用数据类型 / 对象的某个属性watch: {/*** * @param {*} newVal 新值* @param {*} oldVal 旧值*/str(newVal, oldVal) {console.log(newVal, oldVal)},// TODO 侦听对象的某个属性'info.age'(newVal, oldVal) {console.log(newVal, oldVal)}}}
    </script>
    

2.2 对象式侦听器:

  • watch 选项中声明的对象即为对象式侦听器,对象名就是要侦听的数据源,其中对象里面的 handler 函数即为数据源发生变化后要执行的函数,其 参数1新值参数2旧值

  • 配置项

    • 1️⃣ deep

      • watch默认是浅层的,被侦听的属性,仅在被赋新值时,才会触发回调函数,而嵌套属性的变化不会触发;
        • 也就是只有当整个对象被重新赋值的时候会触发,对象中的某个属性值改变不会触发;
      • 如果想侦听所有嵌套的变更,就需要深层侦听器deep: true选项;
      • 如果改变侦听数据的某个嵌套数据,handler也会触发;
      • 深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,开销很大;
      • 注意
        • 如果改变的是整个侦听数据新值就是当前最新的值旧值就是改变之前的值
        • 如果改变的是侦听数据的某个属性新值旧值一样的;
    • 2️⃣ immediate

      • watch默认是懒执行的,仅当数据变化时才会执行回调,但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调,可采用 immediate: true 选项;
    • 3️⃣ flush

      • 默认情况下,用户创建的侦听器回调,都会在Vue组件更新之前被调用,这意味着你在侦听器回调中访问的DOM将是被Vue更新之前的状态
      • 如果想在侦听器回调中能访问被Vue更新之后的DOM,就需要指明 flush: 'post' 选项;
      • 更改 handler() 的执行机制,DOM更新后执行
  • 总结

    • 侦听整个对象:
      • 不开启深度侦听:
        • 只有当对象被重新赋值的时候触发handler()
      • 开启深度侦听:
        • 改变对象某个属性的时候就可以触发;
  • 使用场景:

    • 主要还是用来侦听 - 引用数据类型;
  • 语法

    export default {watch: {侦听的数据: {// deep、immediate、flush配置项根据需要配置,一般都是会加deep的// 开启深度侦听deep: true,handler(newVal, oldVal) {// 相关逻辑}}}
    }
    
  • 示例展示:

    <script>export default {data: () => ({info: {name: '才浅',age: 22}}),methods: {changeInfo() {this.info = {name: '张三',age: 30}}},// TODO 对象式侦听器 - 侦听引用数据类型// NOTE 不开启深度侦听,侦听的是整个对象,只有当整个对象改变的时候才会触发handler(也就是给info重新赋值的时候触发handler)// NOTE 开启深度侦听,改变对象的某个属性,可以触发handler,但是 newVal === oldVal => truewatch: {info: {// 开启深度侦听deep: true,handler(newVal, oldVal) {console.log(newVal, oldVal)}}}}
    </script><template><button @click="changeInfo">对info重新赋值</button><hr><br><h4>侦听 - info</h4><input type="number" v-model.trim.number="info.age"><hr><br>
    </template>
    

2.3 this.$watch() 侦听器

  • 使用 组件实例$watch() 方法来命令式地创建一个侦听器,它还允许你 提前停止侦听器
  • 创建侦听器:
    • 语法
      this.$watch(data, method, object)
      
      • data
        • 侦听的数据,类型为String
      • method
        • 回调函数,参数一为新值,参数二为旧值;
      • object
        • 配置项;
        deep: true ➡ 深度侦听
        immediate: true ➡ 创建时立即触发
        flush: 'post' ➡ 更改回调机制(DOM更新之后,执行回调)
        
  • 停止侦听器:
    • this.$watch()返回值是个函数调用该函数就可以停止该数据的侦听器
  • 示例展示:
    <script>export default {data: () => ({str: '禁止摆烂-才浅',info: {name: '才浅'},student: {age: 22},// 调用该函数,可以停止侦听str数据源stopStrWatch: null,// 调用该函数,可以停止侦听student数据源stopStudentWatch: null}),methods: {changeStudent() {this.student = {name: '才浅',age: 22}}},//  NOTE 生命周期函数mounted() {// TODO 创建侦听器// TODO 侦听 简单数据类型this.stopStrWatch = this.$watch('str', (newVal, oldVal) => {console.log(newVal, oldVal)})// TODO 侦听 对象的某个属性this.$watch('info.name', (newVal, oldVal) => {console.log(newVal, oldVal)})// TODO 侦听 引用数据类型// NOTE 不开启深度侦听// NOTE 改变对象的某个属性,不会触发回调// NOTE 对整个对象进行赋值,可以触发,新旧值不一样// NOTE 开启深度侦听// NOTE 改变 侦听数据的某个属性,新值 === 旧值// NOTE 改变 整个侦听数据(对对象重新赋值),新旧值不一样this.stopStudentWatch = this.$watch('student', (newVal, oldVal) => {console.log(newVal, oldVal)}, {deep: true,})},}
    </script><template>str:<input type="text" v-model.trim="str"><button @click="stopStrWatch">停止侦听str</button><hr><br>info.name:<input type="text" v-model.trim="info.name"><hr><br><button @click="changeStudent">改变student的值</button>student.age:<input type="text" v-model.umber.trim="student.age"><button @click="stopStudentWatch">停止侦听student</button>
    </template>
    

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

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

相关文章

Linux内核介绍and下载

Linux内核介绍and下载 介绍下载下载历史版本 我是将军我一直都在&#xff0c;。&#xff01; 介绍 ● Linux是c语言写成的 ● 符合POSIX标准 ● 作者是芬兰的Linus Torvalds ● 发展依赖于五个重要支柱: unix操作系统、minix操作系统、 GNU计划、POSIX标准和互联网 ● 2.6之后…

打卡--MySQL8.0 二 (用户权限管理)

一、mysql8修改了安全规则&#xff0c;不能像mysql5.7 一次性创建用户并授权&#xff0c;需要分批创建。 1、注意在MySQL8.0版本中创建用户一定要在配置文件中增加如下内容&#xff0c;来兼容旧的程序运行。 default_authentication_pluginmysql_native_password 2、创建用户…

全景解析 Partisia Blockchain:以用户为中心的全新数字经济网络

在区块链世界中&#xff0c;以比特币、以太坊网络为代表的主流区块链奠定了该领域早期的基础&#xff0c;并让去中心化、点对点、公开透明以及不可逆成为了该领域固有的意识形态。事实上&#xff0c;过于透明正在成为区块链规模性采用的一大障碍&#xff0c;我们看到 90% 以上的…

【Attribute】Inspector视图枚举字段范围限定特性

简介 为了提升枚举的复用性&#xff0c;有时候我们可以通过限定枚举字段的范围来避免定义新的枚举类型&#xff0c;例如有一个代表方向的枚举&#xff08;包括None&#xff0c;Left&#xff0c;Up&#xff0c;Right&#xff0c;Down&#xff09;&#xff0c;全局方向&#xff0…

ThreeWayBranch 优化阅读笔记

1. 优化目的 通过重排三分支的 BB 块减少比较指令的执行次数 代码路径: bolt/lib/Passes/ThreeWayBranch.cpp2. 效果 优化前&#xff1a; 注&#xff1a; 黄色数字表示BB块编号&#xff0c; 紫色表示该分支跳转的次数&#xff0c;绿色是代码里BB块的变量名 ThreeWayBranc…

精读《React Conf 2019 - Day2》

1 引言 这是继 精读《React Conf 2019 - Day1》 之后的第二篇&#xff0c;补充了 React Conf 2019 第二天的内容。 2 概述 & 精读 第二天的内容更为精彩&#xff0c;笔者会重点介绍比较干货的部分。 Fast refresh Fast refresh 是更好的 react-hot-loader 替代方案&am…

Spring Cloud Alibaba微服务从入门到进阶(二)

Spring Boot配置管理 1、application.properties 2、application.yml 1.内容格式比较&#xff1a; .properties文件&#xff0c;通过 . 来连接&#xff0c;通过 来赋值&#xff0c;结构上&#xff0c;没有分层的感觉&#xff0c;但比较直接。 .yml文件&#xff0c;通过 &…

Jade 处理XRD并计算半峰宽FWHM、峰面积、峰强度等数据

1.打开软件 2.导入测试的XRD数据 3.平滑数据 4.抠一下基底 5.分析具体数据 6.按住鼠标左键&#xff0c;在峰底部拉一条线&#xff0c;尽量和基底持平 7.结果就出来了&#xff0c;想要的都在里面&#xff0c;直接取值就行

初级爬虫实战——伯克利新闻

文章目录 发现宝藏一、 目标二、简单分析网页1. 寻找所有新闻2. 分析模块、版面和文章 三、爬取新闻1. 爬取模块2. 爬取版面3. 爬取文章 四、完整代码五、效果展示 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

Linux命令深入学习——列出帮助手册,开机关机

linux中有多种方法查看一个不熟悉命令的详细信息&#xff0c;如 ls --help&#xff0c;help ls&#xff0c;man ls&#xff0c;info ls 在linux系统中可以使用命令进行开关机以及相关基础操作 同时在进行写入操作时&#xff0c;可以使用快捷键进行操作

Linux文件与文件系统的压缩

文章目录 Linux文件与文件系统的压缩Linux系统常见的压缩命令gzip&#xff0c;zcat/zmore/zless/zgrepbzip2&#xff0c;bzcat/bzmore/bzless/bzgreppxz&#xff0c;xzcat/xzmore/xzless/xzgrepgzip&#xff0c;bzip2&#xff0c;xz压缩时间对比打包命令&#xff1a;tar打包命令…

马斯克放出豪言,他旗下的xAI要把Grok开源了

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Halcon 使用光流算子检测运动物体

文章目录 算子optical_flow_mg 计算两个图像之间的光流vector_field_length 计算向量场的向量长度select_shape_std 选择给定形状的区域vector_field_to_real 将矢量场图像转换为两个实值图像intensity 计算灰度值的均值和偏差local_max_sub_pix 以亚像素精度检测局部极大值 Ha…

LVS负载均衡群集之NAT与DR模式

一 集群和分布式 企业群集应用概述 群集的含义 Cluster&#xff0c;集群、群集 由多台主机构成&#xff0c;但对外只表现为一个整体&#xff0c;只提供一个访问入口(域名或IP地址)&#xff0c;相当于一台大型计算机。 问题&#xff1f; 互联网应用中&#xff0c;随着站点对…

JVM优化

Java编码执行流程图 a.java ->javac&#xff08;前端编译器&#xff0c;javac属于其中一种&#xff09; ->a.class 和java类库 ->classloader-> Java解释器(一行行解释并运行) 或即时编译器JIT(Just In Time&#xff0c;属于后端编译器)JIT可以将一个方法&#xff…

SpringBoot多数据源切换 多数据源事务解决方案 二

https://zhuanlan.zhihu.com/p/612825647?utm_id0 https://blog.csdn.net/guzhangyu12345/article/details/108559810 SpringBoot多数据源事务解决方案 https://blog.csdn.net/u013407099/article/details/124526396多数据源切换下保证事务解决方案 https://blog.csdn.net/re…

郑州大学2024年3月acm实验室招新赛题解(A-L)

这里感谢一下计算机学术交流协会会长&#xff0c;acm实验室的中坚成员&#xff0c;以及本次比赛的出题人之一孙昱涵将他的账号借给了我。 回顾一下的话&#xff0c;这场的难度其实不是很大&#xff0c;不过对招新的新手来说难度还是挺大的。去掉签到都没签出来的选手的话&…

【C++ Primer Plus学习记录】第6章复习题

1.请看下面两个计算空格和换行符数目的代码片段&#xff1a; //Version 1 while(cin.get(ch)) //quit on eof,EOF(检测文件尾) { if(ch )spaces;if(ch \n)newlines; }//Version 2 while(cin.get(ch)) //quit on eof { if(ch )spaces;else if(ch \n)newlines; } 第…

C++_异常

目录 1、异常的关键字 2、异常的写法 3、异常的使用规则 3.1 规则1 3.2 规则2 3.3 规则3 3.4 规则4 3.5 规则5 4、异常的重新抛出 5、异常的规范 5.1 C98的异常规范 5.2 C11的异常规范 6、C标准库的异常体系 7、异常的优缺点 结语 前言&#xff1a; C的异常…

学习数据节构和算法的第15天

单链表的实现 链表的基本结构 #pragma once #include<stdio.h> typedf int SLTDataType; typedy struct SListNode {SLTDataType data;struct SListNode*next; }SLTNode;void Slisprint(SLTNode*phead);打印链表 #include<stdio.h> void SListPrint(SLTNode*phe…