Vue3中watch监听器及源码学习

 更新时间:2024年01月21日 11:40:24   作者:Unique·Blue  
本文主要介绍了Vue3中watch监听器及源码学习,Watch侦听器在Vue3中特性进行了一些改变和优化,下面来详解的介绍一下基本使用,具有一定的参考价值,感兴趣的可以了解一下

示例均采用 <script setup>,且包含 typescript 的基础用法

前言

在 vue3 中,必须是 refreactive 包裹起来的数据,才可以被 watch 监听到

一、基本使用

1、语法:watch(source, cb, options)

  • source 是监听的目标,有 4 种书写形式:
    • reactive 形式的响应式数据
    • ref 形式的响应式数据
    • 数组形式:监听多个响应式数据时(应该用的不多)
      • 挨个放进 数组 里,如 [响应式数据1, 响应式数据2]
      • cb 对应的 函数参数(新值、旧值)也都是 数组 形式,详见例子
    • 函数形式:若只想监听 reactive 深层中 的 指定属性,该指定属性是
      • 引用类型,不需要函数形式,直接 obj.a.b
      • 非引用类型,比如是一个字符串,则需要使用 函数形式 返回,详见例子
  • cb 是回调函数,(newVal,oldVal) => {}
  • options 是配置项
    • deep: 是否开启深层监听
      • reactive 类型的数据 不需要开启,源码中已做了深层响应式
      • ref 类型的数据如果需要监听到深层,要设置为 true(虽然监听到深层,但是 source 不能指定到深层)
    • immediate: 是否立刻执行
    • flush: watch 的执行顺序。
      • pre 组件更新之前执行(默认)
      • sync 同步执行;
      • post 组件更新之后执行

2、例子

下面代码中,演示了多个情景下的使用

<input type="text" v-model="xiaoman1" />
<br />
<input type="text" v-model="xiaoman2" />
<br />
<input type="text" v-model="message.foo.bar" />
<br />
<input type="text" v-model="message2.foo.bar" />
const xiaoman1 = ref<string>("小满1");
const xiaoman2 = ref<string>("小满2");

const message = ref({
  foo: {
    bar: "aaaaa",
  },
});

const message2 = reactive({
  foo: {
    bar: "aaaaa",
  },
});

watch(xiaoman1, (newVal, oldVal) => {
  console.log("监听单个数据源", newVal, oldVal);
});

// 用数组监听多个数据源,[新值数组], [旧值数组]
watch([xiaoman1, xiaoman2], (newVal, oldVal) => {
  console.log("用数组监听多个数据源,[新值数组], [旧值数组]", newVal, oldVal);
});

// ref 深层监听
watch(
  message,
  (newVal, oldVal) => {
    // 如果是引用类型,新值 和 旧值 是一样的
    console.log("ref 深层监听&立刻执行", newVal, oldVal);
  },
  {
    deep: true, // 深度监听,ref 若需要深度监听,这里要开启
    immediate: true, // callback 立刻先执行一次
    flush: "pre", // 【watch的执行顺序】 pre 组件更新之前调用(默认);sync 同步执行;post 组件更新之后执行
    // flush 属性在 watch 中用的不多,watchEffect中可能用到
  }
);

// reactive 深层监听:不必开启深度监听
watch(
  message2,
  (newVal, oldVal) => {
    // 如果是引用类型,新值 和 旧值 是一样的
    console.log("reactive 深层监听&立刻执行", newVal, oldVal);
  },
  {
    // deep: true, // reactive 不必开启深度监听,源码已做了深层监听
    // immediate: true,
  }
);

// 若只想监听 reactive 深层中的单个属性,(第一个参数)引用类型可直接写,否则使用函数形式
watch(
  message2.foo, // 监听到 foo,foo是引用类型,直接写就行
  // () => message2.foo.bar, // 监听到 bar,需要用函数形式

  (newVal, oldVal) => {
    // 如果是引用类型,新值 和 旧值 是一样的
    console.log("reactive 监听深层中的单个属性", newVal, oldVal);
  }
);

二、源码学习

由于源码较多,这里不做截图

/**
 * 

 * @vue/runtime-core/runtime-core.cjs.prod.js 搜索 function watch
 *
 * -  watch(source, cb, options)
 *
 * -  source 有很多种类型,reactive、ref、数组、函数,所以先判断类型,格式化source
 *    - ref 类型,直接把 value 取出来,赋值给 getter
 *    - reactive 类型,直接把整体赋值给 getter,deep 手动置为 true 即可(reactive已经进行了深度监听)
 *    - 数组类型,做遍历,对每一项再判断类型,分别处理完之后丢进新数组返回
 *          - ref类型,返回.value
 *          - reactive类型,递归处理后返回
 *          - 函数的话,进行加工
 *    - 函数类型
 *          - 判断有没有 cb
 *              - 有 cb 的话,同样也是对函数做了加工赋值给 getter
 *              - 没有 cb,走进 watchEffect(下一章)
 *
 * - deep处理:
 *          - cb、deep 若同时存在,即 有回调函数 且设置了 深度监听,进行 traverse 递归深度监听(当然是更耗时的)
 *
 * - flush处理:先初始化出 scheduler 调度器
 *          - sync 同步执行,scheduler = job
 *          - post 组件更新后,将 job 通过 queuePostRenderEffect 函数处理后再赋值给 scheduler
 *                  - 注意,源码中看到 queuePostRenderEffect 这个函数,一定表示是在组件更新之后再去执行
 *          - pre 组件更新前,queueJob 处理 job 后赋值给 scheduler
 *
 * - ReactiveEffect 收集依赖更新:
 *          - 上面步骤 将 getter、scheduler处理好后作为参数 给到 ReactiveEffect 函数
 *          - ReactiveEffect 收集好依赖之后,有更新的话 就会触发 scheduler,也就是说会执行 job
 *
 *
 * - cb 存在
 *          - immediate 为 true 时,会立即调用一下 job
 *                - 内部会先获取到新值 newVal
 *                - 如果是第一次执行,旧值 oldVal 会置为 undefined
 *                - (执行完这里才会更新)然后 把新值赋值给旧值,为下一次使用准备 (所以如果是对象,新旧值是相等的)
 *          - immediate 为 false 时,
 *                - 先给旧值做初始化,如 oldVal = '小满'
 *                - 依赖如果更新,会触发 scheduler,执行 job
 *                      - job 内新值 newVal = '小满1'
 *                      - 旧值 oldVal 不会走进 undefined,会等于原有的 oldVal = '小满'
 *                      - (执行完这里才会更新)会把 oldVal = '小满1'
 *
 *
 */

到此这篇关于Vue3中watch监听器及源码学习的文章就介绍到这了,更多相关Vue3中watch监听器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • Vue 2 和 Vue 3 中 toRefs函数的不用用法

    Vue 2 和 Vue 3 中 toRefs函数的不用用法

    Vue 是一款流行的JavaScript 框架,用于构建用户界面,在Vue2和 Vue3中,都存在一个名为toRefs的函数,但其行为在这两个版本中有所不同,这篇文章主要介绍了Vue2和Vue3中toRefs的区别,需要的朋友可以参考下
    2023-08-08
  • vuex学习进阶篇之getters的使用教程

    vuex学习进阶篇之getters的使用教程

    getters用于获取state里的数据,它类似于计算属性,如果要获取的数据并没有发生变化的话,就会返回缓存的数据,下面这篇文章主要给大家介绍了关于vuex学习进阶篇之getters的使用教程,需要的朋友可以参考下
    2022-10-10
  • vue3项目中的el-carousel 轮播图的使用

    vue3项目中的el-carousel 轮播图的使用

    Carousel(走马灯)是一种常见的前端组件,通常用于展示多个项目(通常是图片或内容块)的轮播效果,这篇文章主要介绍了vue3项目中的el-carousel 轮播图的使用,需要的朋友可以参考下
    2024-02-02
  • 浅谈mint-ui loadmore组件注意的问题

    浅谈mint-ui loadmore组件注意的问题

    下面小编就为大家带来一篇浅谈mint-ui loadmore组件注意的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • vue实现移动端适方案的完整步骤

    vue实现移动端适方案的完整步骤

    现在的手机五花八门,造就了移动端窗口分辨率繁多的局面,在不同分辨率的屏幕下保持与UI图一致的效果,就成了让前端不得不头疼的问题,下面这篇文章主要给大家介绍了vue实现移动端适方案的相关资料,需要的朋友可以参考下
    2022-10-10
  • 谈谈我在vue-cli3中用预渲染遇到的坑

    谈谈我在vue-cli3中用预渲染遇到的坑

    这篇文章主要介绍了谈谈我在vue-cli3中用预渲染遇到的坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • vue项目部署上线遇到的问题及解决方法

    vue项目部署上线遇到的问题及解决方法

    这篇文章主要介绍了vue项目部署上线遇到的问题及解决方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2018-06-06
  • vue+element开发使用el-select不能回显的处理方案

    vue+element开发使用el-select不能回显的处理方案

    这篇文章主要介绍了vue+element开发使用el-select不能回显的处理方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • Vue学习笔记进阶篇之vue-router安装及使用方法

    Vue学习笔记进阶篇之vue-router安装及使用方法

    本篇文章主要介绍了Vue学习笔记进阶篇之vue-router安装及使用方法,具有一定的参考价值,有兴趣的可以了解一下
    2017-07-07
  • vue3 开始时间与结束时间比较验证(结束时间需要大于开始时间)

    vue3 开始时间与结束时间比较验证(结束时间需要大于开始时间)

    本文通过示例代码介绍了vue3 开始时间与结束时间比较验证(结束时间需要大于开始时间)的相关操作,代码简单易懂,感兴趣的朋友跟随小编一起看看吧
    2024-07-07

最新评论