Vue3从入门到实战:深度了解相关API

shallowRef

  1. 作用:创建一个响应式数据,但只对顶层属性进行响应式处理。

  2. 用法:

    let myVar = shallowRef(initialValue);
  3. 特点:只跟踪引用值的变化,不关心值内部的属性变化。

shallowReactive

  1. 作用:创建一个浅层响应式对象,只会使对象的最顶层属性变成响应式的,对象内部的嵌套属性则不会变成响应式的

  2. 用法:

    const myObj = shallowReactive({ ... });
  3. 特点:对象的顶层属性是响应式的,但嵌套对象的属性不是。

1.shallowRef 与 shallowReactive

我们直接使用代码解释如何使用。 

新建App.vue实现了一个简单的求和和修改人物信息的功能。

我们使用 ref 创建了名为 sum 和 person 的响应式引用

changeSum 函数在点击按钮时将 sum 的值加1,changeName 函数将 person 的姓名修改为 "李四",changeAge 函数将 person 的年龄加1,changePerson 函数将整个 person 对象替换为一个新的对象。 

展示:

当我点击按钮时:

现在,我将shallowRef来替换掉Ref 

这是为什么呢?

因为shallowRef是浅层响应的意思,它只能调用第一层,深层次的则不行

 你可以这么理解,就只能有一个.value,后面再跟就没有响应了。

 而shallowReactive的作用跟shallowRef一样的,不赘述了

作用:

shallowRef 的作用是将一个普通的 JavaScript 对象或数组转换为响应式对象,但不会递归地将对象或数组中的每个属性或元素都转换为响应式。这意味着当你修改对象或数组的属性或元素时,不会触发视图的更新。

与之相反,ref 会将对象或数组的每个属性或元素都转换为响应式。这意味着当你修改对象或数组的属性或元素时,视图将会自动更新。

换言之,如果我们修改了对象内部属性或数组内部元素,视图不会自动更新。只有当我们修改了对象或数组本身时,视图才会更新以反映这种变化。这种行为适用于当我们只关心对象或数组的引用变化,而不关心其内部属性或元素的具体变化时。这样可以提高性能,减少不必要的监测和更新操作。

总而言之:

通过使用 shallowRef() 和 shallowReactive() 来绕开深度响应。浅层式 API 创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理,避免了对每一个内部属性做响应式所带来的性能成本,这使得属性的访问变得更快,可提升性能。


2.readonly 与 shallowReadonly

  1. 作用用于创建一个对象的深只读副本。

  2. 用法

    const original = reactive({ ... });
    const readOnlyCopy = readonly(original);
  3. 特点

    • 对象的所有嵌套属性都将变为只读。

    • 任何尝试修改这个对象的操作都会被阻止(在开发模式下,还会在控制台中发出警告)。

readonly 和 shallowReadonly 是 Vue 3 中提供的用于创建只读的响应式引用的函数。

概念: 

想象一下,你有一个对象或数组,你希望它在被使用的时候不能被修改。就好像你给别人一个只读的物品,他们可以查看它,但不能改变它的内容。

readonly 的作用就是将一个对象或数组转换为只读的响应式引用。这意味着当你使用 readonly 创建的变量时,它是只读的,你不能直接修改它的值。如果你尝试修改它,Vue 3 会发出警告,并且不会更新视图。

shallowReadonly 与 readonly 类似,也是用于创建只读的响应式引用,但它是浅层只读的。这意味着,如果你使用 shallowReadonly 创建的变量是一个对象或数组,你可以阅读它的属性或元素,但不能修改属性或元素的值。然而,如果属性或元素是对象或数组,你可以修改它们的值。这样做是为了保持引用的只读特性,同时允许引用内部的对象或数组进行更改。

readonly

下面运用例子解释:

这段代码是一个网页应用,有两个按钮和两个显示结果的文本。你可以点击按钮来增加两个求和的结果。 

甚至你会注意代码第22行报错,就是因为sum2提示只能读不能改。 

报错的原因简单讲就是,里面不能是数据类型的参数,要放入的是具有响应式的参数,同时要把后面的.value去掉。

其中,sum1 是一个可以被修改的变量,表示一个求和结果。而 sum2 是一个只读的变量,它的值始终与 sum1 相同,但不能直接修改它。

当你点击 "点我sum1+1" 按钮时,sum1 的值会加1,而页面上显示的结果会更新。但是,当你点击 "点我sum2+1" 按钮时,尽管 sum2 的值与 sum1 相同,但它是只读的,不能直接修改它。因此,点击这个按钮并不会改变 sum2 的值,也不会更新页面上的结果。

这在某些情况下很有用,例如当你想向其他组件传递数据,但不希望其他组件能够修改它。readonly 可以确保数据的稳定性和可靠性,避免不必要的副作用。

展示:

 补充:

 

报错的原因简单讲就是,里面不能是数据类型的参数,要放入的是具有响应式的参数,同时要把后面的.value去掉。


shallowReadonly:

作用:与 readonly 类似,但只作用于对象的顶层属性。

用法:

const original = reactive({ ... });
const shallowReadOnlyCopy = shallowReadonly(original);

特点:

  • 只将对象的顶层属性设置为只读,对象内部的嵌套属性仍然是可变的。

  • 适用于只需保护对象顶层属性的场景。

下面举例子解释:

 car1 是一个包含汽车信息的对象,包括品牌、选项等。car2 是一个浅层只读的变量,它与 car1 相关联,但只能修改其属性的值,而不能修改整个对象或其属性的引用。 

App.vue代码:

<template>
	<div class="app">
		<h2>当前sum1为:{{ sum1 }}</h2>
		<h2>当前sum2为:{{ sum2 }}</h2>
		<h2>当前car1为:{{ car1 }}</h2>
		<h2>当前car2为:{{ car2 }}</h2>
		<button @click="changeSum1">点我sum1+1</button>
		<button @click="changeSum2">点我sum2+1</button>
		<button @click="changeBrand2">修改品牌(car2)</button>
		<button @click="changeColor2">修改颜色(car2)</button>
		<button @click="changePrice2">修改价格(car2)</button>
	</div>
</template>

<script setup lang="ts" name="App">
	import { ref,reactive,readonly,shallowReadonly } from "vue";

	let sum1 = ref(0)
	let sum2 = readonly(sum1)
	let car1 = reactive({
		brand:'奔驰',
		options:{
			color:'红色',
			price:100
		}
	})
	let car2 = shallowReadonly(car1)

	function changeSum1(){
		sum1.value += 1
	}
	function changeSum2(){
		sum2.value += 1 //sum2是不能修改的
	}

	function changeBrand2(){
		car2.brand = '宝马'
	}
	function changeColor2(){
		car2.options.color = '绿色'
	}
	function changePrice2(){
		car2.options.price += 10
	}
</script>

<style scoped>
	.app {
		background-color: #ddd;
		border-radius: 10px;
		box-shadow: 0 0 10px;
		padding: 10px;
	}
	button {
		margin:0 5px;
	}
</style>


3.toRaw 与 markRaw

关于toRaw:

  1. 作用:用于获取一个响应式对象的原始对象, toRaw 返回的对象不再是响应式的,不会触发视图更新。

    官网描述:这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。不建议保存对原始对象的持久引用,请谨慎使用。

    何时使用? —— 在需要将响应式对象传递给非 Vue 的库或外部系统时,使用 toRaw 可以确保它们收到的是普通对象

下面举一个例子解释:

我们使用 reactive 函数创建了一个名为 person 的响应式对象,其中包含姓名和年龄的属性。然后,我们使用 toRaw 函数获取了 person 对象的原始非响应式版本,并将其保存在 rawPerson 变量中。

toRaw 函数用于获取一个响应式对象的原始对象,即没有被包装成响应式的普通对象。在这个例子中,我们将响应式的 person 对象传递给 toRaw 函数,它返回了一个与 person 相同属性和值的普通对象。 

在控制台中,我们打印了 person 和 rawPerson 的值,以展示它们之间的区别。

展示:

注意:

 不建议保存对原始对象的持久引用,请谨慎使用。

就是以上使用 toRaw 函数获取了 person 对象的原始非响应式的操作。谨慎使用是为了防止person和Rawperson搞混。


关于markRaw:

  1. 作用标记一个对象,使其永远不会变成响应式的。

    例如使用mockjs时,为了防止误把mockjs变为响应式对象,可以使用 markRaw 去标记mockjs

然后用markRaw()标记 

 所以被markRaw标记一个对象后,使其永远不会变成响应式的。

补充:

使用场景:使用mockjs时,为了防止误把mockjs变为响应式对象,可以使用 markRaw 去标记mockjs

Mock.js是一个用于生成随机数据和模拟HTTP请求响应的JavaScript库。它可以帮助前端开发人员在开发过程中模拟接口数据,以便更好地进行前后端分离和并行开发。

 1.安装Mock.js

2.用mockjs标记

 

App.vue代码:

<template>
	<div class="app">
		<h2>姓名:{{ person.name }}</h2>
		<h2>年龄:{{ person.age }}</h2>
		<button @click="person.age += 1">修改年龄</button>
		<hr>
		<h2>{{ car2 }}</h2>
		<button @click="car2.price += 10">点我价格+10</button>
		
	</div>
</template>

<script setup lang="ts" name="App">
	import { reactive,toRaw,markRaw } from "vue";
	import mockjs from 'mockjs'

	/* toRaw */
	let person = reactive({
		name:'tony',
		age:18
	})
	// 用于获取一个响应式对象的原始对象 
	let rawPerson = toRaw(person)
	// console.log('响应式对象',person)
	// console.log('原始对象',rawPerson)

	let car = markRaw({brand:'奔驰',price:100})
	let car2 = reactive(car)

	console.log(car)
	console.log(car2)

	let mockJs = markRaw(mockjs)






</script>

<style scoped>
	.app {
		background-color: #ddd;
		border-radius: 10px;
		box-shadow: 0 0 10px;
		padding: 10px;
	}
	button {
		margin:0 5px;
	}
</style>

4.customRef

概念:

我们知道,当我们在Vue中使用ref函数创建响应式数据时,它会帮助我们包装一个值,并且在这个值发生变化时通知相关的组件进行更新。这样我们就可以在组件中直接使用这个响应式数据,并且可以轻松地对其进行修改和访问。

customRef就是一个更高级的工具,它允许我们自定义响应式引用的行为。我们可以定义一个自己的跟踪器逻辑,来决定何时触发更新、如何处理值的变化等等。这样可以满足一些特殊的需求,例如延迟更新、异步更新等。

所以,你可以将customRef看作是一个可以根据你的需求定制的响应式引用。它给了你更多的自由度和控制权,让你可以实现一些定制化的响应式行为,以适应你的项目需求。

作用创建一个自定义的ref,并对其依赖项跟踪和更新触发进行逻辑控制。

举例子解释:

现在有一个业务需求,当我在输入框修改时,标延迟1s后才显示,但是普通的ref是会立即显示,没有办法,只能用customRef(自定义的ref)

以下步骤:

1.引入customRef包,写出customRef的回调函数

2.回调函数里面写出return

3.写出get(),set()

4.导入跟踪器(track)和触发器(trigger)

 重点:

跟踪器(track)用于侦听数据的变化,而触发器(trigger)用于触发相应的操作。

5.在里面修改延迟1s的业务

代码解析:

调用clearTimeout(timer)来清除之前的延时器(如果存在)。这样可以确保在设置新的延时器之前,之前的延时器已经被取消。然后,使用setTimeout函数创建一个新的延时器,它会在1000毫秒(即1秒)后执行一个回调函数。

回调函数中的代码会将传入的value赋给initValue,即更新了数据。然后,通过trigger()方法通知Vue数据msg发生了变化,使其重新渲染相关的组件。

展示:


App.vue代码:

<template>
	<div class="app">
		<h2>{{ msg }}</h2>
		<input type="text" v-model="msg">
	</div>
</template>

<script setup lang="ts" name="App">
	import {ref,customRef} from 'vue'
	

	// 使用Vue提供的默认ref定义响应式数据,数据一变,页面就更新
	//let msg = ref('你好')

	// 使用Vue提供的默认ref定义响应式数据,数据一变,页面就更新
	let initValue = '你好'
	let timer:number
	let msg = customRef((track,trigger)=>{
		return{
			// get何时调用? - msg被读取时
		 get(){
			track();//告诉Vue数据msg很重要,你要对msg进行持续关注,一旦msg变化就去更新
			return initValue;

		 },
		  // set何时调用? - msg被修改时
		 set(value){
			clearTimeout(timer)
			timer = setTimeout(()=>{
				initValue = value
				trigger(); //通知Vue一下数据msg变化了
			},1000);
			
		 }
		}
	})


</script>

<style scoped>
	.app {
		background-color: #ddd;
		border-radius: 10px;
		box-shadow: 0 0 10px;
		padding: 10px;
	}
	button {
		margin:0 5px;
	}
</style>

但是这样写还是写不够方便简洁,以后有新的业务时要修改的地方太多

还可以更近一步的完善,如下:

1.封装一个hoolks,将逻辑代码写入进去。

代码解析:

方法会返回一个具有延迟更新功能的数据对象。你可以把它想象成一个计时器。

当你在组件中使用该方法时,你需要传递两个参数:初始值和延迟时间。初始值就是数据的初始内容,而延迟时间表示在用户输入后等待多长时间才进行更新。

在内部,这个函数使用了Vue提供的`customRef`函数,它可以帮助我们创建一个自定义的数据跟踪器。

这个数据跟踪器有两个方法:`get`和`set`。当其他部分代码读取数据时,就会调用`get`方法。然后,我们返回数据的当前值。

当其他部分代码修改数据时,就会调用`set`方法。在这个方法中,我们首先清除之前的计时器,以防止数据更新发生太频繁。然后,我们创建一个新的计时器,在延迟时间后执行一个回调函数。在回调函数中,我们将数据的值更新为新值,并通知Vue数据发生了变化。

最后,函数返回一个包含延迟更新的数据对象,你可以在组件中使用它。当你读取这个数据时,Vue会自动追踪它,并在数据发生变化时更新相关的组件。而当你修改这个数据时,它会等待一段时间后才进行更新操作,以避免过于频繁的更新。

2.在App.vue中使用该文件

useMsgRef.ts代码:

import { customRef } from "vue";

export default function(initValue:string,delay:number){
  // 使用Vue提供的customRef定义响应式数据
  let timer:number
  // track(跟踪)、trigger(触发)
  let msg = customRef((track,trigger)=>{
    return {
      // get何时调用?—— msg被读取时
      get(){
        track() //告诉Vue数据msg很重要,你要对msg进行持续关注,一旦msg变化就去更新
        return initValue
      },
      // set何时调用?—— msg被修改时
      set(value){
        clearTimeout(timer)
        timer = setTimeout(() => {
          initValue = value
          trigger() //通知Vue一下数据msg变化了
        }, delay);
      }
    }
  })
  return {msg}
}

App.vue代码:

<template>
	<div class="app">
		<h2>{{ msg }}</h2>
		<input type="text" v-model="msg">
	</div>
</template>

<script setup lang="ts" name="App">
	import {ref} from 'vue'
	import useMsgRef from './useMsgRef'

	// 使用Vue提供的默认ref定义响应式数据,数据一变,页面就更新
	// let msg = ref('你好')

	// 使用useMsgRef来定义一个响应式数据且有延迟效果
	let {msg} = useMsgRef('你好',3000)

</script>

<style scoped>
	.app {
		background-color: #ddd;
		border-radius: 10px;
		box-shadow: 0 0 10px;
		padding: 10px;
	}
	button {
		margin:0 5px;
	}
</style>

总结:

本文介绍了一些Vue 3中的响应式API,包括shallowRefshallowReactivereadonlyshallowReadonlytoRawmarkRawcustomRef

  • shallowRefshallowReactive是用于创建响应式数据的函数。shallowRef创建一个浅层响应式引用,而shallowReactive创建一个浅层响应式对象。
  • readonlyshallowReadonly用于创建只读的响应式数据。readonly创建一个深层只读响应式对象,而shallowReadonly创建的对象只有顶层属性是只读的。
  • toRawmarkRaw用于处理响应式数据的原始值。toRaw用于获取响应式对象的原始值,而markRaw用于标记一个对象,使其在响应式转换时保持不可响应。
  • customRef是一个自定义的响应式引用创建函数,允许开发者定义自己的跟踪器逻辑,实现更高级的响应式行为。

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

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

相关文章

【MySQL】表的基本约束

文章目录 1、约束类型1.1NOT NULL约束1.2UNIQUE&#xff1a;唯一约束1.3DEFAULT&#xff1a;默认值约束1.4PRIMARY KEY&#xff1a;主键约束1.5FOREIGN KEY&#xff1a;外键约束 2、表的设计2.1一对一2.2一对多2.3多对多 1、约束类型 关键字解释NOT NULL指示某列不能存储NULL值…

点赞列表查询列表

点赞列表查询列表 BlogController GetMapping("/likes/{id}") public Result queryBlogLikes(PathVariable("id") Long id) {return blogService.queryBlogLikes(id); }BlogService Override public Result queryBlogLikes(Long id) {String key BLOG_…

【C++航海王:追寻罗杰的编程之路】C++11(上)

目录 1 -> C11简介 2 -> 统一的列表初始化 2.1 -> {}初始化 2.2 -> std::initializer_list 3 -> 声明 3.1 -> auto 3.2 -> decltype 3.3 -> nullptr 1 -> C11简介 在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C…

Debian

文章目录 前言一、使用root用户操作二、配置用户使用sudo命令三、添加桌面图标显示1.打开终端2.执行安装命令3.执行成功后重启4. 打开扩展&#xff0c;配置图标 四、图形化界面关闭和打开五、设置静态IP1.查询自己系统网络接口2.修改网络配置文件 总结 前言 Debian 系统在安装…

基于Springboot+Vue的Java项目-在线文档管理系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

RUOYI 若依 横向菜单

保留移动端适配 小屏适配 菜单权限等 可轻松进行深度自定义菜单样式 以及分布 仅支持横向布局 如需源码 教程等 ➕ wx 技术支持 wx : 17339827025

【IEEE出版 | 中山大学主办 | 往届会后2-4个月EI检索】第五届电子通讯与人工智能学术会议(ICECAI 2024)

第五届电子通讯与人工智能国际学术会议&#xff08;ICECAI 2024&#xff09; 2024 5th International Conference on Electronic communication and Artificial Intelligence 第五届电子通讯与人工智能国际学术会议&#xff08;ICECAI 2024&#xff09;将于2024年5月31日-6月…

淘宝订单交易详情查询API是淘宝开放平台提供的接口,可以通过该接口获取淘宝订单的详细信息。

淘宝订单交易详情查询API是淘宝开放平台提供的接口&#xff0c;可以通过该接口获取淘宝订单的详细信息。通过该API&#xff0c;你可以获取订单的基本信息、商品信息、买家信息、物流信息等。 具体使用该API需要进行以下步骤&#xff1a; 在淘宝开放平台注册开发者账号&#xf…

QA测试开发工程师面试题满分问答15: 讲一讲InnoDB和MyISAM

InnoDB和MyISAM是MySQL中两种常见的存储引擎&#xff0c;它们在数据存储和处理方面有着显著的区别。让我们逐一来看一下它们的区别、原理以及适用场景。 区别&#xff1a; 事务支持&#xff1a;InnoDB是一个支持事务的存储引擎&#xff0c;而MyISAM不支持事务。事务是一种用于维…

L2-045 堆宝塔

L2-045 堆宝塔 分数 25 全屏浏览 切换布局 作者 陈越 单位 浙江大学 堆宝塔游戏是让小朋友根据抓到的彩虹圈的直径大小&#xff0c;按照从大到小的顺序堆起宝塔。但彩虹圈不一定是按照直径的大小顺序抓到的。聪明宝宝采取的策略如下&#xff1a; 首先准备两根柱子&#xff…

C++运算符重载和日期类的实现

运算符重载 参数个数与操作个数应该一致(双目操作符就是2个参数,同时参数中包括this) 不能被重载的运算符 " .* "运算符的作用 .*就是用来调用成员函数指针的 调用 1.显式调用 运算符重载可以显式调用 eg. 2.转换调用 运算符重载增强了程序的可读性 bool operato…

SpringBoot版本配置问题与端口占用

前言 ​ 今天在配置springboot项目时遇到了一些问题&#xff0c;jdk版本与springboot版本不一致&#xff0c;在使用idea的脚手架创建项目时&#xff0c;idea的下载地址是spring的官方网站&#xff0c;这导致所下载的版本都是比较高的&#xff0c;而我们使用最多的jdk版本是jdk…

使用不锈钢微型导轨的优势!

微型导轨是一种专门用于在紧凑空间内执行高精度的机器运动控制的导轨设备。其特点是尺寸小、精确度高、刚性好、平稳性好以及使用寿命长。微型导轨的材质种类多样&#xff0c;一般包括钢、不锈钢、铝合金等。目前来说&#xff0c;不锈钢材质的使用率最为频繁&#xff0c;那么使…

Vue3从入门到实践:深度了解新组件

1.Teleport 概念&#xff1a;Teleport&#xff08;传送门&#xff09;是一个新的特性&#xff0c;用于在DOM中的任意位置渲染组件。它允许你将组件的内容渲染到DOM中的另一个位置&#xff0c;而不受组件层次结构的限制。 下面举出例子解释&#xff1a; 1.新建App.vue文件作…

数据结构—单链表

1、链表的概念及结构 1.1链表的概念 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;但在逻辑上确是连续、顺序的&#xff0c;而数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 1.2链表的结构 如下图&#xff1a; 逻辑上的链表&#xff0c;pList是指…

AOP基础

一、AOP概述 AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实就是面向特定方法编程。 使用场景&#xff1a;①记录操作日志&#xff1b;②权限控制&#xff1b;③事务管理等。 优势&#xff1a;①代码无侵入…

【GPTs分享】GPTs分享之 AskYourPDF Research Assistant​

一、简介 AskYourPDF Research Assistant 是一款高级人工智能研究助手&#xff0c;专门设计用于帮助用户高效从PDF文件和文章中提取信息。它结合了深度学习技术和自然语言处理能力&#xff0c;以便用户能够快速地查询、总结及处理文档内容&#xff0c;并能够生成与文章内容相关…

依泉LXSY LXLY电子远传水表说明书MODBUS-RTU通讯协议

这款水表的通讯协议主要包括以下内容&#xff1a; 概述 传输方式 数据帧格式 地址码 功能码 数据区 CRC校验码 生成一个CRC的流程 通讯应用格式详解 寄存器地址 通讯接口 表盘地址 这是厂家给的通讯协议&#xff0c;我亲测可以读取到水表的读数&#xff0c;精度只…

怎么理解load_average

之前我讲了cpu使用率的问题&#xff0c;cpu使用率是我们监控中非常关注的指标。 但是工作中&#xff0c;我们经常遇到业务应用已经很慢了&#xff0c;但是cpu利用率显示很低。 这种时候&#xff0c;你会发现top中load很高。 在top中&#xff0c;load average后面有3个数字。…

AtCoder ABC349 A-D题解

比赛链接:ABC349 Problem A: 签到。 #include <bits/stdc.h> using namespace std; const int maxn105; int A[maxn]; int main(){int N;cin>>N;int ans0;for(int i1;i<N;i){cin>>A[i];ans-A[i];}return 0; } Problem B: 开2个桶即可&#xff0c;具体…