学习vue3第六节(vue3 中 computed watch watchEffect)

1、computed

计算属性:computed 原理:不管是 Vue2 中还是在 Vue 3 中,计算属性会基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。 在对赋值求值或者大数据求值会起到一定性能优化的作用。

在 Vue 中计算属性会计算出一个新的属性,并将这个属性挂载到 vm(Vue 实例上)。而相对的还有侦听器 watch,侦听器是监听 vm 上已经存在的响应式属性,所以可以用侦听器监听计算属性。

计算属性本质是一个惰性求值的观察者,具有缓存性,只有当依赖发生改成时,才会重新求值。侦听器是当依赖数据发生改变时就会执行回调。

在使用场景上,计算属性适合在一个数据被多少数据影响时使用,而侦听器适合在一个数据影响多个数据。接下来我们就通过源码来看看 computed 的实现原理。

而在vue3 中,computed 有两种形式:
1、直接接收一个getter函数,并且getter()函数会返回一个不可改变的响应式ref对象,注意是不可改变的,
2、接受一个对象,对象中包含 get()、set() 方法,通过get()、set()进行读写ref对象

computed / watch / watchEffect 含义
监听数据的异同
监听一个属性,多个属性,ref对象,reactive对象

<template>
  <div class="watch-container">

    年龄:{{ age }}
    <br>
    姓名:{{ name }}
    <br>
    职业:{{ person.job }}
    <br>
    爱好:{{ person.love }}
  </div>
  <div>
    otherPerson==={{ JSON.stringify(otherPerson) }}
    年龄:{{ otherPerson.age.value }}
  </div>
  <button @click="handleChangeAge()">change age</button>
  <div>==============</div>
  <div>personAllName:{{ personAllName }}</div>
  <div>lastName: {{ lastName }}</div>
  <br>
  <button type="primary" @click="handleChangeLastName">change person laset name</button>

</template>
<script setup>
import { ref,  reactive, computed} from 'vue'
const age = ref(0)
const name = ref('Andy')
const person = reactive({
  job: '搬砖',
  love: '音乐'
})
// 1、传入getter 函数
const otherPerson = computed(() => {
  return {
    age,
    name,
    ...person
  }
},
{
  onTrack(e) {
    // 当 otherPerson.age 被追踪为依赖时触发
    debugger
  },
  onTrigger(e) {
    // 当 otherPerson.age 被更改时触发
    debugger
  }
}
)
const handleChangeAge = () => {
  age.value++
  console.log('====')
}

// 2、 传入对象,可以进行读写操作
let firstName = ref('zhang')
let lastName = ref('Andy')
const personAllName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  set(otherPersonName) {
    lastName.value = otherPersonName
  }
})
const handleChangeLastName = () => {
  personAllName.value = '下一个肖申克' + "$"
}
</script>

实现方式上,vue3与vue2中的computed() 都是基于响应式依赖进行缓存的,
但是 vue3 中的computed需要依赖于 ref() 和 reactive() 响应属性的值来实现,而effect则是依赖于computed() 来实现的

当我们在调用 computed 方法时,就会在这里需要统一做下区分,同时调用实现类 ComputedRefImpl,这个方法比较简单,接下来我们重点分析下类 ComputedRefImpl。

<script>
function computed(getterOrOptions, ...) {
  let getter;
  let setter;
  const onlyGetter = isFunction(getterOrOptions);
  if (onlyGetter) {
    getter = getterOrOptions;
    setter = () => {
      console.warn('Write operation failed: computed value is readonly');
    }
    ;
  } else {
    getter = getterOrOptions.get;
    setter = getterOrOptions.set;
  }
  const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
  ...
  return cRef;
}

// ComputedRefImpl 类
class ComputedRefImpl {
  constructor(getter, _setter, isReadonly, isSSR) {
    this._setter = _setter;
    this.dep = undefined;
    this.__v_isRef = true;
    this._dirty = true;
    // 创建effect对象,生成watcher监听函数,并将值赋给实例的 effect属性, 
    this.effect = new ReactiveEffect(getter, () => {
      if (!this._dirty) {
        this._dirty = true;
        triggerRefValue(this);
      }
    });
    this.effect.computed = this;
    this.effect.active = this._cacheable = !isSSR;
    // 根据传入是否有setter函数来决定是否只读;设置ref是否为只读对象,
    this["__v_isReadonly" /* IS_READONLY */] = isReadonly;
  }
  get value() {
    const self = toRaw(this);
    trackRefValue(self);
    if (self._dirty || !self._cacheable) {
      self._dirty = false;
      self._value = self.effect.run();
    }
    return self._value;
  }
  set value(newValue) {
    this._setter(newValue);
  }
}
</script>

若需要computed 实际案例,请留言说明具体业务需求,在线提供代码

2、watch

侦听器,只要监听的响应式属性|对象|数组发生变化就会触发回调函数:

watch(
  source,
  callback,
  {
    deep:true,
    immediate:true,
    flush:'pre'|'post'|'async',
    onTrack(){
      // 调试
    },
    onTrigger(){
      debugger
    },
    once: true // 是否只执行一次
  }
)

侦听的数据源 source :
1、响应式对象reactive;
2、一个ref属性(包括computed),
3、一个getter()函数;
4、多个数据源组成的数组;

<script setup>
import { ref, reactive, watch } from 'vue'
const firstName = ref('张')
const lastName = ref('Andy')

const person = reactive({
  name: 'Andy',
  job: '专业搬砖'
})
</script>

// 监听单个ref

watch(firstName, (newValue, oldValue) => {
  console.log('firstName===',newValue, oldValue)
})

// 监听reactive对象

watch(person, (newValue, oldValue) => {
  // 此时newValue === oldValue // true 是相当的
  // 因为他们是同一个对象
})

// 若要监听reactive对象中的某个属性,需要如下:
// 若要监听 person中job改变,使用getter函数

watch(
  () => person.job, // 第一个参数需要是 函数,
  (newValue, oldValue) => {
    // 此时可以监听到 newValue 与 oldValue 不相等
  },
  {
    deep: true, // 默认false, 是否启用深度监听,与vue2 语法一样,
    immediate: true // 默认false, 是否立即执行,在页面初始化时候需要执行回调函数时,可以添加此属性,第一次调用时旧值是 undefined,
    flush: 'pre'|'post' | 'async', //默认是pre, 如果想在侦听器回调中能访问被 Vue 更新之后的所属组件的 DOM,可以使用 post,如果想同步执行可以使用 async;(分别有对应的语法糖,watchPostEffect(),watchAsyncEffect(), 下节说明)
    onTrack(){},
    onTrigger(){},
    once: false, // 默认false 是否只执行一下 v3.4 之后才有
  }
)

// 监听多数据源

watch(
  [lastName, ()=> person.name], 
  ([lastNameNew, personNameNew], [lastNameOld, personNameOld]) => {
    // 此时回调函数中需要是对应的新旧值数组,顺序与 source 中数组属性顺序一致;
})

// 停止侦听器

const stopWatch = watch(firstName, () => {
	//
})

// 执行 stopWatch() 即可停止侦听器;

// 清除副作用,比如深度监听、立即执行时候,里面有请求后台的接口,我们希望的是使用最新的数据参数,进行处理逻辑??? 超出三界之外,后续补充!!!

3、watchEffect

// watchEffect 立即运行一个函数,同时响应式的追踪其依赖,并且能够在依赖发生变化时候,重新执行函数,可以监听页面中所有ref、reactive声明的属性、对象、等响应式变量;
// 动态新加的属性 同样会监听到,收集所有依赖监听执行;
//

let stopWatchEffect = watchEffect(() => {
// 第一个参数:回调函数
}, {
// 第二参数:
  flush: 'pre', 'post', 'sync', // 默认是pre,参考watch对应用法
  onTrack(e) { // 调试
    debugger
  },
  onTrigger(e) {
    debugger
  }
},
)

// watch 需要显性的指定需要监听的对象,属性,可以自己配置对应的属性,如是否立即执行(immediate: true),是否需要深度监听(deep: true)
// watchEffect 则会自动收集需要响应式对象属性,并且会在对象或属性发生变化时候,立即执行副作用函数,而不需要手动配置;

欢迎各位大神在线批评指导!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Aigtek超声功率放大器产品介绍

超声功率放大器是一种特殊类型的功率放大器&#xff0c;专门用于增强和放大超声信号的功率。它在医疗、工业和科学领域中得到广泛应用。 一、超声功率放大器的基本概述 超声功率放大器是一种能够将低功率超声信号放大到更高功率水平的设备。它是超声系统的关键组成部分&#xf…

力扣1. 两数之和

思路&#xff1a;用一个map存放 已遍历过的元素和下标&#xff1b; 若当前元素是nums[i], 且该元素的另一半 target-nums[i] 在已遍历过的map里面&#xff0c;则返回两个元素的下标&#xff1b; class Solution {public int[] twoSum(int[] nums, int target) {int[] ans new…

腾讯云服务器多少钱1个月?2024一个月收费阿济格IE吧

2024腾讯云服务器多少钱一个月&#xff1f;5元1个月起&#xff0c;腾讯云轻量服务器4核16G12M带宽32元1个月、96元3个月&#xff0c;8核32G22M配置115元一个月、345元3个月&#xff0c;腾讯云轻量应用服务器61元一年折合5元一个月、4核8G12M配置646元15个月、2核4G5M服务器165元…

数据结构:详解【顺序表】的实现

1. 顺序表的定义 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存储。动态顺序表与数组的本质区别是——根据需要动态的开辟空间大小。 2. 顺序表的功能 动态顺序表的功能一般有如下几个&#xff1a; 初始化顺序表打印顺序…

PlantUML Integration 编写短信服务类图

PlantUML Integration 写一个类图&#xff0c;主要功能为 1、编写一个serviceSms短信服务类&#xff1b; 2、需要用到短信的地方统一调用基建层的服务即可&#xff1b; 3、可以随意切换、增加短信厂商&#xff0c;不需要更改场景代码&#xff0c;只需要更改application.yml 里面…

Redis数据结构对象中的对象共享、对象的空转时长

对象共享 概述 除了用于实现引用计数内存回收机制之外&#xff0c;对象的引用计数属性还带有对象共享的作用。 在Redis中&#xff0c;让多个键共享同一个值对象需要执行以下两个步骤: 1.将数据库键的值指针指向一个现有的值对象2.将被共享的值对象的引用计数增一 目前来说…

【Godot4.2】2D导航01 - AStar2D及其使用方法

概述 对于2D平台跳跃或飞机大战&#xff0c;以及一些直接用键盘方向键操控玩家的游戏&#xff0c;是根本用不到寻路的&#xff0c;因为只需要检测碰撞就可以了。 但是对于像RTS或战棋这样需要操控玩家到地图指定位置的移动方式&#xff0c;就绝对绕不开寻路了。 导航、碰撞与…

微信小程序接口请求出错:request:fail url not in domain list:xxxxx

一、微信小程序后台和开发者工具配的不一样导致了这个错误 先说结论&#xff1a; 开发者工具配置了https://www.xxx.cn/prod-api/ 微信后台配置了 https://www.xxx.cn 一、最开始 开发者工具配置了https://www.xxx.cn:7500 微信后台配置了 https://www.xxx.cn 报错:reques…

代码随想录算法训练营第53天 | 1143.最长公共子序列 ,1035.不相交的线 ,53. 最大子序和

动态规划章节理论基础&#xff1a; https://programmercarl.com/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 1143.最长公共子序列 题目链接&#xff1a;https://leetcode.cn/problems/longest-common-subsequence/description/ 思路&…

ASP .Net Core ILogger日志服务

&#x1f433;简介 ILogger日志服务是.NET平台中的一个内置服务&#xff0c;主要用于应用程序的日志记录。它提供了灵活的日志记录机制&#xff0c;允许开发者在应用程序中轻松地添加日志功能。以下是其主要特点和组件&#xff1a; ILogger接口&#xff1a;这是ILogger日志服…

电脑数据安全新利器:自动备份文件的重要性与实用方案

一、数据安全的守护神&#xff1a;自动备份文件的重要性 在数字化时代&#xff0c;电脑中的文件承载着我们的工作成果、个人回忆以及众多重要信息。然而&#xff0c;数据丢失的风险无处不在&#xff0c;无论是硬件故障、软件崩溃&#xff0c;还是恶意软件的攻击&#xff0c;都…

JupytetNotebook常用的快捷键

Jupyter Notebook 中常用的快捷键&#xff1a; 切换到命令模式&#xff1a;按 Esc 键。切换到编辑模式&#xff1a;按 Enter 键。运行当前单元格并选择下面的单元格&#xff1a;按 Shift Enter。运行当前单元格并插入新的单元格在下面&#xff1a;按 Alt Enter。删除当前单元…

【Vue3】Vue3中的编程式路由导航 重点!!!

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

test测试类-变量学习

test测试类 作用&#xff1a;标记到类上成为测试类&#xff0c;标记到方法上成为测试方法 变量&#xff1a;测试类的变量&#xff0c;在测试类括号中应用 1、invocationCount变量 意思是这个方法应该被调用的次数。 在测试框架中&#xff0c;特别是当使用参数化测试或数据驱动…

HarmonyOS(鸿蒙)快速入门

一:下载开发工具 鸿蒙的开发工具叫DevEco 下载点击 其他部分都一直next 就行,这个页面出现的install 建议都点击install 然后单独选择安装目录 可能存在的问题 就是之前安装nodejs&#xff08;比如自己开发web或者RN等情况&#xff09;版本低 等情况 所以建议你单独安装一次 …

Avalon总线学习

Avalon总线学习 avalon总线可以分为&#xff1a; Avalon clock interface Avalon reset interface Avalon Memory mapped interface Avalon iterrupt interface Avalon streaming interface Avalon tri-state conduit interface Avalon conduit interface 1、Avalon c…

杨氏矩阵的查找(复杂度<O(N))

题目&#xff1a; 解释&#xff1a;时间复杂度小于O(N)即不要一个一个的去遍历查找。 思路&#xff1a; 一个33的二维数组如图所示&#xff1a; 一&#xff1a;先找到一个最关键的数字&#xff0c;3&#xff08;下标为0,2&#xff09; 关键数的关键之处在于&#xff08;处于…

SpringBoot + MyBatisPlus分页查询

文章目录 1.思路分析2.分页查询后端实现1.com/sun/furn/config/MybatisConfig.java 注入MyBatisPlus分页拦截器2.com/sun/furn/controller/FurnController.java 添加方法3.postman测试 3.分页查询前端实现1.src/views/HomeView.vue 引入分页导航条组件2.src/views/HomeView.vue…

外包干了6天,技术明显进步。。。

我是一名大专生&#xff0c;自19年通过校招进入湖南某软件公司以来&#xff0c;便扎根于功能测试岗位&#xff0c;一晃便是近四年的光阴。今年8月&#xff0c;我如梦初醒&#xff0c;意识到长时间待在舒适的环境中&#xff0c;已让我变得不思进取&#xff0c;技术停滞不前。更令…

springboot企业级抽奖项目-整体展示

项目地址 GitHub - kiorr/lottery: 企业红包雨项目 star截图q&#xff1a;3353441618可以领取资料 原型效果 前台 后台 业务分析 项目介绍 项目概述 京东的红包雨大家可能都参与过&#xff0c;在某段时间内随机发放不同的红包 本项目为一个通用的红包雨模式抽奖系统&…
最新文章