Vue响应式核心

news/2024/10/18 16:54:45/

响应式数据:Ref、Reactive

<script setup>
import { ref, reactive } from 'vue';
// ref 基础类型数据
const name = ref('高启强');
// reactive 引用类型数据object, array, function
const obj = reactive({
  name'高启盛',
  age28,
});
// ref数据在js中需要使用.value访问
console.log(name.value)
// reactive数据不用.value
console.log(obj.name)
</script>

<template>
  <div>
    <p>{{ name }}</
p>
    <p>{{ obj.name }}</p>
  </div>
</
template>

ref和reactive的区别

  • ref数据在js中需要使用.value访问,reactive数据不用.value
  • ref创建基础类型数据, 如string,number,boolean。 reactive创建引用类型数据object, array, function

只读数据:readonly

readonly的作用顾名思义就是不允许修改,通过readonly包装的数据是不可修改的,有些像const。如果要是尝试修改也是无效的,并且控制台会有警告信息。

readonly适用于数据传给别的地方但不允许修改数据,只能在当前逻辑修改的情况。比如通过readonly将一个ref数据包裹,将包裹后的readonly数据返回到其他地方用,但是别的地方无法修改。要修改只能更改原ref数据,ref数据改了readonly的数据也会跟着改

<script>
import { ref, readonly } from 'vue'
export default {setup() {// 响应式数据const nameData = ref('高启强')// 不可修改 (上面的ref数据变了,这个readonly数据会跟着一起变)const name = readonly(nameData)// 修改控制台有警告:[Vue warn] Set operation on key "value" failed: target is readonly. name.value = '高启盛'console.log(name.value);  // 这里打印的还是:高启强return {name}}
}
</script>

readonly和const有什么不同?

  • readonly可以直接修改整个对象, 不可以修改其中的属性。
<script>
import { reactive, readonly } from 'vue'
export default {setup() {let obj = reactive({name: '高启强',})let person1 = readonly(obj)// readonly不能修改其中的某个属性  person1.name = '高启盛'console.log(person1.name);  // 高启强(修改失败)// readonly可以修改整个对象person1 = {name: '高启盛2号'}console.log(person1.name);  // 高启盛2号 (修改成功)}
}
</script>
  • const不能直接修改整个对象,可以修改其中的属性。
<script>
export default {setup() {const person1 = {name: '高启强',}// const可以修改其中的属性  person1.name = '高启盛'console.log(person1.name);  // 高启盛(修改成功)// const不可以修改整个对象,并且控制台报错,下面的console也不执行了person1 = {name: '高启盛2号'}console.log(person1.name);  // 高启盛2号 (修改失败)}
}
</script>

计算属性:computed

  • 传入函数:computed是一个方法,一般使用就是传入一个回调函数并返回计算的结果。computed方法会得到最终的结果。
<script setup>
import { ref, computed } from 'vue';

const num = ref(2);
const price = ref(12);

const totalPrice = computed(() => num.value * price.value);

console.log(totalPrice); // 24
</script>
  • 传入对象:computed也可以传入对象,对象中有set和get方法,在set的时候可以做一些其他的处理。
<script setup>
import { ref, computed } from 'vue';

const num = ref(2);
const price = ref(12);

// let totalPrice = computed(() => num.value * price.value);
let totalPrice = computed({
  get() => num.value * price.value,
  set(val) => {
    // 设置totalPrice的时候改变num的值
    num.value += val;
    return val + 1;
  },
});
// 设置totalPrice,num会根据totalPrice设置的值改变
totalPrice.value = 33;
console.log(num); // 35
</script>

修改totalPrice的时候改变num的值,修改totalPrice为33,num会根据totalPrice设置的值改变。

数据监听:watch

watch的基础用法

watch用来监听数据的变化,跟vue2中的作用一样,只是写法不一样。

需要注意的是监听一定要放到前面,修改数据放到监听的后面,这样才能监听到。如果需要监听前面的修改需要开启deep深度监听

<script>
import { ref, watch } from 'vue'
export default {setup() {const name = ref('高启强')// 要先监听后修改,在这里修改数据写在监听前面是监听不到的,需开启immediate立即触发才可以监听到name.value = '高启强1号'// 开始监听watch(name, (newValue, oldValue) => {// 上面的修改没有监听到,监听到了下面的修改console.log(newValue, oldValue);  // 高启强2号, 高启强1号})name.value = '高启强2号'}
}
</script>

watch的配置参数

一般watch不做其他配置的话用前两个参数就够了,第一个是监听的数据,第二个是数据改变时的回调函数,如果需要修改watch配置参数就需要第三个参数了,第三个参数是一个对象,就是一些配置属性。比如常用的deep深度监听、**immediate**立即触发配置。

深度监听

在第三个参数中传入deep:true选项就可以深度监听对象,就是对象里面的对象也可以监听。

立即触发

在第三个参数中传入immediate:true选项就可以在第一次数据创建的时候就开始监听

<script>
import { ref, watch } from 'vue'
export default {setup() {const name = ref('高启强')watch(name, (newValue, oldValue) => {// 上面的修改没有监听到,监听到了下面的修改console.log(newValue, oldValue);  // 高启强2号, 高启强1号}, {deep: true,immediate: true})name.value = '高启强1号'}
}
</script>

控制台打印结果:

高启强 undefined

高启强1号 高启强

watch监听多个

watch第一个参数最常用的就是直接传入一个数据进行监听,其实第一个参数还可以传数组和函数,传数组代表监听多个,传函数可以只监听reactive中的某个属性。

监听多个:传入数组监听多个数据,回调函数中返回的newValue和oldValue也会是一个数组,和传入的顺序一致。

<script>
import { reactive, watch } from 'vue'
export default {setup() {const obj = reactive({name: '张三',age: 35})// 监听reactive数据其中的一个属性,这里监听name和age两个数据watch([() => obj.name, () => obj.age], ([newName, newAge], [oldName, oldAge]) => {console.log(newName, oldName);  // 李四 张三console.log(newAge, oldAge);  // 42 35})obj.name = '李四'obj.age = 42}
}
</script>

watch停止监听

watch方法会返回一个可执行的方法,执行这个方法就可以取消监听

const stop = watch(source, callback)

// 当已不再需要该侦听器时:
stop()

watchEffect()

watchEffect和watch的作用都是监听数据,不同的是watchEffect不需要指定监听谁,第一个参数直接传入监听回调函数,会根据函数中用到的数据进行自动监听,只要其中任何一个数据变了就会执行。

<script>
import { reactive, watchEffect } from 'vue'
export default {setup() {const obj = reactive({name: '张三',age: 35})watchEffect(() => {console.log(obj.name); // 张三})// 已经开始监听obj.nam, 只要obj.nam改变了就会执行watchEffect函数中的内容}
}
</script>

副作用清理、取消监听

watchEffect的回调参数有一个参数,就是取消副作用的方法。

当在watchEffect里面执行了一个方法后需要取消或者关闭的时候可以使用清除副作用方法,比如在watchEffect里面执行了一个setInterval定时器,或者通过window.addEventListener订阅了一个事件,这些最后都是需要关闭或者取消的。所以就可以通过取消副作用方法进行清除方法。

取消副作用方法的执行时机

1.当组件被销毁的时候会执行

2.当取消监听的时候会执行

<script>
import { watchEffect } from 'vue'
export default {setup() {const stop = watchEffect((onCleanup) => {const timer = setInterval(() => {console.log('a')}, 1000)// 当组件被销毁的时候该函数执行// 当取消监听的时候会执行onCleanup(() => {clearInterval(timer)})})// 取消监听 会执行onCleanup方法stop()}
}
</script>

修改执行时机

第二个参数中的flush属性用来更改执行时机,更改这个属性可以修改是在组件更行前执行还是组件更新后执行。

  • flush:'pre'在组件更新前执行 默认为'pre'
  • flush:'post'在组件更新后执行
  • flush:'sync强制效果始终同步触发。然而,这是低效的,应该很少需要。
<script>
import { ref, watchEffect, onBeforeUpdate } from 'vue'
export default {setup() {const name = ref('张三')onBeforeUpdate(() => {console.log('onBeforeUpdate');})watchEffect(() => {console.log('watchEffect');console.log(name.value);}, {//'pre' 在组件更新前运行,默认为'pre'//'post'在组件更新后运行//'sync'强制效果始终同步触发。然而,这是低效的,应该很少需要。flush:'post'})function changeName() {name.value = '李四'console.log('修改数据');}return {name,changeName}}
}
</script><template><div>{{ name }}</div><button @click='changeName'>按钮</button>
</template>

点击按钮会执行changeName事件,然后组件就会更新

flush:pre 执行结果:

修改数据 watchEffect 李四 onBeforeUpdate

flush: post 执行结果

修改数据 onBeforeUpdate watchEffect 李四

watchPostEffect()

watchEffect() 使用 flush: 'post' 选项时的别名。

watchSyncEffect()

watchEffect() 使用 flush: 'sync' 选项时的别名。

本文由 mdnice 多平台发布


http://www.ppmy.cn/news/63316.html

相关文章

flink cdc原理与使用

flink cdc原理与使用 1 cdc 介绍1.1 cdc简介与对比1.2 基于日志的 CDC 方案介绍 2 基于 Flink SQL CDC 的数据同步方案实践2.1 案例 1 : Flink SQL CDC JDBC Connector2.2 案例 2 : CDC Streaming ETL2.3 案例 3 : Streaming Changes to Kafka 3 Flink SQL CDC 的更多应用场景…

node.js 处理路径问题

node.js 处理路径问题 什么是path路径模块 path模块是Node.js官方提供的、用来处理路径的模块。它提供了一系列的方法和属性&#xff0c;用来满足用户对路径的处理需求。 例如&#xff1a; path.join()方法&#xff0c;用来将多个路径片段拼接成一个完整的路径字符串path.ba…

《通过并行蒙特卡洛方法合成桡动脉的光电容积图(PPG),及其与体重指数(BMI)的相关性》阅读笔记

目录 一、论文摘要 二、论文十问 Q1&#xff1a;论文试图解决什么问题&#xff1f; Q2&#xff1a;这是否是一个新的问题&#xff1f; Q3&#xff1a;这篇文章要验证一个什么科学假设&#xff1f; Q4&#xff1a;有哪些相关研究&#xff1f;如何归类&#xff1f;谁是这一课…

VHDL的基本语法(一)

1 VHDL基本结构 1 实体 Entity&#xff1a;描述所设计的系统的外部接口信号&#xff0c;定义电路设计中所有的输入和输出端口 2 结构体 Architecture&#xff1a;描述系统内部的结构和行为 3 包集合 package&#xff1a;存放各设模块能共享的数据类型、常数和子程序等&#xf…

C++11多线程:std::thread创建线程和std::async创建异步任务的区别,std::async创建异步任务后没有被推迟执行。

系列文章目录 文章目录 系列文章目录前言一、thread和async的区别1.1 新线程和异步任务1.2 std::async和std::thread最明显的不同&#xff0c;就是async有时候并不创建新线程。1.3 std::async和std::thread的区别1.4 std::async不确定性问题的解决 二、使用方法2.1 std::async创…

动态规划--01背包问题

01背包问题 背包问题题目最优解结构性质状态转移方程方程理解 递归实现核心思想代码实现用例测试 画表非递归实现核心思路代码实现画表展示 计算哪些物品放入算法思想代码实现 背包问题 题目 0-1背包问题:给定n种物品和一背包。物品的重量是w;,其价值为v; ,背包的容量为C。问…

Android studio单独导入官方例程camera-calibration

1.官方例程camera-calibration 2.将官方例程camera-calibration copy到AndroidStudioProjects项目目录下 3修改AndroidManifest.xml <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android“http://schemas.android.com/apk/res/andr…

医院智能导诊系统,医院导航解决方案

随着现代医院规模不断扩大&#xff0c;功能区域越来越细化&#xff0c;面对复杂的楼宇结构&#xff0c;集中的就诊人流&#xff0c;患者在就诊中经常会面临找不到目的地的困境&#xff0c;就诊体验变差。针对这个问题&#xff0c;一些面积和规模都比较大的医院&#xff0c;已经…