Vue3学习记录(一)--- 组合式API之基础概念和变量声明

一、组合式API基础

1、简介

​ 组合式 API (Composition API) 是Vue3和Vue2的v2.7之后版本中的全新特性,是一系列API的的集合(响应式API、生命周期钩子、依赖注入等等),其风格是基于函数的组合,以一种更直观、更灵活的方式来书写Vue单文件组件。但是组合式 API并不属于函数式编程,因为函数式编程主要强调的是数据不可变,而以 Vue 中数据可变的、细粒度的响应性系统为基础的。

​ 接下来我们讲述的相关知识点,都是基于Vue3的组合式API来进行的。

2、优势
更好的复用性

​ 组合式API最大的优势在于可以通过组合函数的方式,将组件进行任意颗粒度的拆分和组合,这样就大大提高了代码的可维护性和复用性。

更灵活的代码组织性

​ 同时,组合式API可以将处理某一逻辑的所有相关代码,放置在相邻区域内,解决了选项式API中将处理统一逻辑的代码分散在不同的选项中,在查看时需要上下来回进行滚动切换的弊端,方便后期将相关逻辑抽出,封装为单独组件。官方示例图片如下,相同颜色的代码块,表示处理某一逻辑的相关代码:

在这里插入图片描述

更好的TS支持

​ 组合式API主要利用基本的变量和函数,这些东西本身就是类型友好的,因此组合式API对于TypeScript的支持性更好。

更小的打包体积

​ 使用组合式API(<script setup>)的单文件组件中的组件模板(<template>)在打包时,会被编译成一个内联函数,与JS代码位于同一作用域内,可以直接访问定义的变量和函数,无需像选项式API一样依赖this这个上下文对象来访问属性。由于变量名可以被压缩,但是对象的属性名不能被压缩,所以组合式API对于代码压缩更友好,打包后的体积也就更小。

3、使用方法
方法一:使用setup() 钩子函数(不常用)

​ 这种方法并不常用,通常只用于以下两种情况:① 在非单文件组件中使用组合式API时,例如:在html文件中引入Vue。② 在基于选项式API的单文件组件中集成使用组合式API时,例如:在Vue2中使用。

​ 通过使用setup()函数来定义响应式数据,然后将该函数返回的对象暴露给模板和组件实例,然后就可以在选项式API中通过this来获取相关属性,如果在模板中使用变量,则无需使用this。但是在setup()函数中,是无法访问组件实例的,也就是this对象。

<script>
// 引入响应式API
import { ref } from 'vue'export default {// 使用setup()钩子函数setup() {// 声明响应式变量const count = ref(0)// 返回值会暴露给模板和其他的选项式 API return {count}},mounted() {// 通过this来访问声明的响应式变量console.log(this.count) // 0}
}
</script><template><!-- 在模板中使用声明的变量 --><button @click="count++">{{ count }}</button>
</template>

setup()函数具有两个参数:第一个参数为props,用于获取组件实例中接受的props参数,会根据props参数的变化,响应式的变化;第二个参数为context,表示一个Setup上下文对象,该对象暴露了一些常用的API对象:

export default {// 组件接收父组件传递过来的props数据props: {title: String},// setup的第一个参数为props 第二个参数为contextsetup(props, context) {// 以props.xxx的形式方式访问数据 不要使用数据解构 这样会失去响应性console.log(props.title)// 透传 Attributes(非响应式的对象,等价于 $attrs)console.log(context.attrs)// 插槽(非响应式的对象,等价于 $slots)console.log(context.slots)// 触发事件(函数,等价于 $emit)console.log(context.emit)// 暴露公共属性(函数)console.log(context.expose)}
}

​ 更多详细用法请查阅:组合式 API:setup()。

方法二:使用<script setup>(常用)

​ 该方法是我们在Vue3中的主流用法,通过在单文件组件的<script>标签中增加setup,标识该标签内部使用组合式API,大大简化了setup()函数的繁琐语法。而且在<script setup>中的顶层(非局部)中导入的模块、声明的变量和函数,可以在当前单文件组件中直接使用。

<!-- 在script标签中增加setup -->
<script setup>
// 引入要使用的API
import { ref, onMounted } from 'vue'
// 声明变量
let count = ref(0);
// 声明函数
const addCount = () => {// 在函数中修改变量 需要调用.valuecount.value++;
}
// 在生命周期中使用声明的变量
onMounted(() => {// 获取变量值需要调用.valueconsole.log('mounted---',count.value)
})
</script><template><!-- 在模板中使用声明的变量 无需使用.value --><button @click="addCount">{{ count }}</button>
</template>

二、变量声明

1、ref(推荐)

​ 在组合式API中,推荐使用ref()函数来声明响应式变量,该函数可以声明任何类型的值,包括StringNumber等简单类型,也包括深层嵌套的对象、数组以及JS内置的Map、Set等内置数据结构。简单类型的变量可以ref()可以直接声明,复杂类型的变量则会在内部直接调用 reactive()函数来实现。

​ 想要使用 ref()函数,需要先从vue对象中将该函数引入到当前组件中:

// 引入ref()函数API
import { ref } from 'vue'

ref()函数接收一个参数,这个参数为声明的响应式变量的初始值,然后函数会返回一个带有.value属性的ref对象。我们需要使用let/const/var声明一个变量,来接收ref()函数返回的响应式对象,至此,一个响应式变量就创建成功了。

// 通过ref()函数声明响应式变量
const count = ref(0)

​ 通过ref()函数声明的变量,如果是在<script setup>的顶层(非局部)中声明的,那可以在整个单文件组件中访问。在组件的<script setup>标签中修改或访问时,需要通过变量名.value的形式访问,但是在组件的<template>模板中使用变量,包括{{ }}模板语法、事件监听器的表达式等等情况,可以直接使用变量名,此时响应式变量会自动解包,获取其value属性。

<script setup>// 省略前面的引入和声明// 直接访问count 返回一个含有value属性的对象console.log(count) // { value: 0 }// 访问count.valueconsole.log(count.value) // 0// 修改变量值count.value++// 再次访问变量console.log(count.value) // 1
</script><template><!-- 在模板中使用声明的变量 无需使用.value --><button @click="count++">{{ count }}</button>
</template>

​ 在组件的<template>模板中只有顶级的ref变量才会被自动解包,如果是非顶级的ref变量,则不会解包,例如在一个对象中将属性值声明为ref变量:

<script setup>// 省略前面的引入和声明// 顶级的ref变量 let obj3 = ref({ count: 0 });// 非顶级的ref变量 let obj4 = { count: ref(0) };
</script><!--  自动解包 显示:0 -->
<p>{{ obj3.count }}</p>
<!-- 此时 ref 是文本插值的最终计算值 会自动解包 因此显示:0 -->
<p>{{ obj4.count }}</p>
<!-- 自动解包 显示:1 -->
<p>{{ obj3.count + 1 }}</p>
<!-- 此时 ref 不是文本插值的最终计算值 不自动解包 显示:[object Object]1  -->
<p>{{ obj4.count + 1 }}</p>
2、reactive

reactive()函数是组合式API声明响应式变量的另外一种方式,只能用来声明复杂类型的数据变量(ObjectArrayMapSet等),不能声明简单类型的数据变量。想要使用 reactive()函数,需要先从vue对象中将该函数引入到当前组件中:

// 引入reactive()函数API
import { reactive } from 'vue'

reactive()函数接收一个参数,表示声明的响应式变量的初始对象值,然后函数会返回一个原始数据对象的 Proxy对象,该对象是响应式的。最终再使用let/const/var声明一个变量,来接收reactive()函数返回的响应式对象,至此,一个响应式变量就创建成功了:

// 通过reactive()函数声明响应式变量
const countObj = reactive({ count: 0 })

​ 通过reactive()函数声明的变量,如果是在<script setup>的顶层(非局部)中声明的,那可以在整个单文件组件中访问。在组件的<script setup>标签中和在<template>模板中使用变量时,直接使用变量名即可:

<script setup>// 省略前面的引入和声明// 直接调用变量名 会返回一个代理对象console.log(countObj); // Proxy(Object) {count: 0}// 调用代理对象的属性console.log(countObj.count); // 0// 代理对象的属性值可以直接修改countObj.count++;console.log(countObj.count); // 1
</script><template><!-- 在模板中使用声明的变量 无需使用.value --><button @click="state.count++">{{ state.count }}</button>
</template>

reactive() 返回的是原始对象的Proxy代理对象,它和原始对象是不全等的,只有Proxy对象是响应式的,更改原始对象不会触发更新。而且为保证访问代理的一致性,对同一个原始对象调用 reactive() 会总是返回同一个的Proxy对象,而对一个已存在的Proxy对象调用 reactive() 会返回其本身。

// 创建一个原始对象
let obj = { count: 0 };
// 使用reactive()创建一个响应式对象
let countObj = reactive(obj);
// 代理对象和原始对象并不相等
console.log(obj === countObj); // false
// 在同一个原始对象上重复调用reactive()会返回相同的代理
console.log(countObj === reactive(obj)); // true
// 在代理对象上再次调用reactive()会返回其本身
console.log(countObj === reactive(countObj)); // true

​ 如果reactive()函数包裹的变量初始值为一个多层嵌套对象的数据,reactive()会深层的转换代理对象,无论嵌套多少层,都会将每一层对象转换为代理对象,最终返回的Proxy对象内部全部都是响应式的。

// 声明一个嵌套对象
let obj2 = { test: { count: 0 } };
// 使用reactive()创建一个响应式对象
let countObj2 = reactive(obj2);

​ 对于一个通过reactive()创建的响应式对象,如果我们使用对象解构,将其简单类型的属性解构为一个变量时,或者将简单类型的属性传递给函数作为参数时,变量和参数都会失去响应性的效果:

	// 当解构时,count 已经与 countObj.count 断开响应式连接let { count } = countObj// 修改解构出的count的变量值  不会影响countObj的 countcount++console.log(count) // 1console.log(countObj.count) // 0// 该函数接收到的是一个普通的数字 无法响应式的追踪到countObj.count的变化testFunction(countObj.count) {// ...}// 如果想要保持响应式的特性 则需要将整个响应式对象传入其中testFunction2(countObj) {// ...}

​ 如果通过reactive()创建的响应式数组或原生集合类型(如 Map) 中,使用ref()声明的变量作为元素,其不会被自动解包,需要通过.value的形式访问:

// 响应式数组中使用ref()声明的变量作为元素
const books = reactive([ref('Vue 3 Guide')])
// 这里需要 .value
console.log(books[0].value)
// 响应式集合中使用ref()声明的变量作为元素
const map = reactive(new Map([['count', ref(0)]]))
// 这里需要 .value
console.log(map.get('count').value)
3、shallowRef

shallowRef()函数是ref()函数的浅层作用形式,函数接收一个参数,这个参数为声明的响应式变量的初始值,但是函数不会返回一个Proxy代理对象,返回的是原始数据本身。此时只有对变量.value的访问是响应式的。如果想要转换为响应式的原始数据是复杂类型的数据变量,则更改其内部的属性值并不会有响应式,只有变更整个value的值才会触发响应式。

​ 如果原始数据是具有多层嵌套的复杂数据类型,也只有对.value的访问是响应式的。因此shallowRef() 常常用于对大型数据结构的性能优化或是与外部的状态管理系统集成,避免对大型数据的响应性开销。

// 引入 shallowRef() API
import { ref, shallowRef } from 'vue'// 声明一个js对象
const obj = { num: 1 };
// 利用ref声明一个响应式变量
const state = ref(obj)
// 利用shallowRef声明一个浅层响应式变量
const state2 = shallowRef(obj)
// 输出两个变量
console.log(state.value); // 一个Proxy代理对象:Proxy(Object) {num: 1} 
console.log(state2.value); // 一个普通对象:{num: 1}
// 判断响应式变量和原对象是否相等
console.log(state.value === obj); // false
// 判断浅层响应式变量和原对象是否相等
console.log(state2.value === obj); // true
// 判断浅层响应式变量和响应式变量是否相等 
console.log(state2.value === state.value); // false// 直接修改内部属性值不会触发响应式
state.value.count = 2;// 直接修改value属性才会触发响应式
state.value = { count: 3 };

shallowRef()函数返回的是原始数据本身,如果我们在组件被挂载之前修改浅层响应式变量的内部属性值,依旧会被响应式监听到。例如:在<script setup>中声明浅层变量后,直接修改其内部属性值,或者在onBeforeMount()生命周期钩子函数中修改其内内部属性值。

<script setup>// 引入相关APIimport { onBeforeMount, onMounted, shallowRef } from 'vue'// 声明一个js对象const obj = { num: 1 };// 利用shallowRef声明一个浅层响应式变量const state2 = shallowRef(obj);// 在组件挂载之前 修改变量的内部属性值 页面显示会更新onBeforeMount(() => {state2.value.num = 1111;});// 在组件挂载之后 修改变量的内部属性值 页面显示不会更新onMounted(() => {console.log(state2.value); // {num: 1111}state2.value.num = 2222;console.log(state2.value); // {num: 2222}})
</script><!-- 最终渲染显示为:1111 -->
<p>{{ state2.num }}</p>
4、shallowReactive

shallowReactive()函数时reactive()函数的浅层作用形式,通过该函数的声明的响应式对象变量,只有根对象中的属性才是响应式的,如果变量包含嵌套的对象结构,则嵌套对象的属性值不会被转换成响应式,只有整个替换属性值时才会触发响应式。

// 引入 shallowReactive API
import { shallowReactive } from 'vue'// 声明一个原始对象
const obj = { num: 1, next: { count: 1 } };
// 声明一个浅层响应式对象
const state = shallowReactive(obj);
// 输出该对象
console.log(state); // Proxy(Object) {num: 1, next: {…}}// 直接修改根属性 可以触发响应式
state.num = 2222;
// 直接修改嵌套属性 不会触发响应式
state.next.count = 2222;
// 重新赋值嵌套属性 可以触发响应式
state.next = { count: 3333 };

​ 如果我们在组件被挂载之前修改其嵌套对象的属性值,依旧会被响应式监听到。例如:在<script setup>中声明浅层对象变量后,直接修改其嵌套对象的属性值,或者在onBeforeMount()生命周期钩子函数中修改其嵌套对象的属性值。

<script setup>// 引入相关APIimport { onBeforeMount, onMounted, shallowRef } from 'vue'// 声明一个原始对象const obj = { num: 1, next: { count: 1 } };// 声明一个浅层响应式对象const state = shallowReactive(obj);// 在组件挂载之前 修改变量的内部属性值 页面显示会更新onBeforeMount(() => {state.next.count = 2222;});// 在组件挂载之后 修改变量的内部属性值 页面显示不会更新onMounted(() => {console.log(state.next.count); // {num: 2222}state.next.count = 3333;console.log(state.next.count); // {num: 3333}})
</script><!-- 最终渲染显示为:2222 -->
<p>{{ state.next.count}}</p>

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

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

相关文章

【Unity3D小技巧】Unity3D中UI控制解决方案

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 在开发中总是会控制UI界面&#xff0c;如何优雅的控制UI界面是…

02-Java抽象工厂模式 ( Abstract Factory Pattern )

抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是围绕一个超级工厂创建其他工厂 该超级工厂又称为其他工厂的工厂 在抽象工厂模式中&#xff0c;接口是负责创建一个相关对象的工厂&#xff0c;不需要显式指定它们的类 每个生成的工厂都能按照工厂模式提供对象 …

CDS view与替代对象

一&#xff0c;简介 替代对象是指用一个CDS view指派给一个透明表或常规数据库视图&#xff0c;使得透明表或常规数据库视图的访问重定向到该CDS view。 替代有诸多要求&#xff1a; 字段数量一致且同名对应&#xff0c;顺序可以不一致对应的字段数据类型长度等必须一致CDS v…

在Linux下搭建自己的私有maven库并部署和发布自定义jar依赖和自定义maven插件(三)开发和发布自己开发的maven插件

系列文章目录 在Linux下搭建自己的私有maven库并部署和发布自定义jar依赖和自定义maven插件(二)发布自己开发的jar包 文章目录 系列文章目录在Linux下搭建自己的私有maven库并部署和发布自定义jar依赖和自定义maven插件(二)发布自己开发的jar包 前言一、插件需求二、maven自定…

前端JavaScript篇之对 rest 参数的理解、ES6中模板语法与字符串处理

目录 对 rest 参数的理解ES6中模板语法与字符串处理 对 rest 参数的理解 rest参数是一种在函数定义中使用的特殊语法&#xff0c;它允许函数接受任意数量的参数&#xff0c;并将它们收集到一个数组中。通俗地说&#xff0c;rest参数就像是一个容器&#xff0c;用来存放函数接收…

帮管客CRM SQL注入漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

2024年美赛B题:寻找潜水器 Searching for Submersibles 思路模型代码解析

2024年美赛B题&#xff1a;寻找潜水器 Searching for Submersibles 思路模型代码解析 【点击最下方群名片&#xff0c;加入群聊&#xff0c;获取更多思路与代码哦~】 问题翻译 海上游轮迷你潜艇&#xff08;MCMS&#xff09;是一家位于希腊的公司&#xff0c;专门制造能够将人…

如何在Windows部署GoLand并通过SSH远程连接Linux服务器

文章目录 1. 安装配置GoLand2. 服务器开启SSH服务3. GoLand本地服务器远程连接测试4. 安装cpolar内网穿透远程访问服务器端4.1 服务器端安装cpolar4.2 创建远程连接公网地址 5. 使用固定TCP地址远程开发 本文主要介绍使用GoLand通过SSH远程连接服务器&#xff0c;并结合cpolar内…

Vue 环境准备

1.安装vscode https://code.visualstudio.com/ 2.安装开发vue所需插件&#xff1a; Vetur —— 语法高亮、智能感知、Emmet等 包含格式化功能&#xff0c; AltShiftF &#xff08;格式化全文&#xff09;&#xff0c;CtrlK CtrlF&#xff08;格式化选中 代码&#xff0c;两…

在 Elastic Agent 中为 Logstash 输出配置 SSL/TLS

要将数据从 Elastic Agent 安全地发送到 Logstash&#xff0c;你需要配置传输层安全性 (TLS)。 使用 TLS 可确保你的 Elastic Agent 将加密数据发送到受信任的 Logstash 服务器&#xff0c;并且你的 Logstash 服务器从受信任的 Elastic Agent 客户端接收数据。 先决条件 确保你…

防御保护 防火墙的双机热备和带宽管理实验

需求&#xff1a; 办公区设备可以通过电信和移动链路上网&#xff08;多对多的NAT&#xff0c;并需要保留一个公网IP不能用来转换&#xff09;分公司设备可以通过总公司的移动和电信链路访问DMZ区的http服务器分公司内部的客户端可以通过公网地址访问到内部的服务器FW1和FW4组…

Unity | YooAssetV2.1.0 + HybridCLR热更新

目录 一、项目更改 二、使用YooAsset热更 1.资源配置 2.资源构建 3.将两个文件夹下的资源上传CDN服务器 4.修改代码 5.运行效果 本文记录利用YooAssetHybridCLR来进行资源和dll的更新。YooAsset使用的是新版V2.1.0。相比于旧版&#xff0c;dll(原生文件)和资源要建两个p…

AI-数学-高中-18-三角函数-同角三角函数关系及计算

原作者视频&#xff1a;三角函数】5同角三角函数关系&#xff08;易中档&#xff09;_哔哩哔哩_bilibili 辅助三角形&#xff08;计算速度快&#xff09;&#xff1a;1.画一个辅助计算的任意直接三角形&#xff1b;2.利用初中方法先计算sin、cos、tan值&#xff1b;3.看象限确定…

Python机器学习:样本划分之验证集法

评估机器学习模型优劣的标准是模型的泛化能力&#xff0c;所以关注的应该是泛化误差而不是经验误差&#xff0c;一味追求经验误差的降低&#xff0c;就会导致模型“过拟合”现象。但是泛化误差是难以直接观察到的&#xff0c;我们应该如何选择泛化能力比较好的模型呢&#xff1…

蓝桥杯---垒骰子

赌圣atm晚年迷恋上了垒骰子&#xff0c;就是把骰子一个垒在另一个上边&#xff0c;不能歪歪扭扭&#xff0c;要垒成方柱体。经过长期观察&#xff0c;atm 发现了稳定骰子的奥秘&#xff1a;有些数字的面贴着会互相排斥&#xff01;我们先来规范一下骰子&#xff1a;1的对面是4&…

【Docker篇】Linux安装Docker、docker安装mysql、redis、rabbitmq

1.Linux安装docker 官方帮助文档&#xff1a;Install Docker Engine on CentOS | Docker Docs 1.1安装命令 # 1. 卸载之前的dockersudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate…

RK3568平台 安卓hal3适配usb camera

一.RK安卓hal3 camera框架 Camera hal3 在 android 框架中所处的位置如上图&#xff0c; 对上&#xff0c;主要实现 Framework 一整套 API 接口&#xff0c;响应其 控制命令&#xff0c;返回数据与控制参数结果。 对下&#xff0c; 主要是通 V4l2 框架实现与 kernel 的交互。3a…

linux 下mongodb7版本怎么连?

概述&#xff1a;linux下的mongodb7版本默认是没有安装客户端的&#xff0c;需要下载shell客户端才能连&#xff0c;下载之后解压&#xff0c;不需要编译&#xff0c;进入bin目录就能自己运行&#xff0c;。 安装&#xff1a; linux 下mongodb7版本没有安装客户端需要当地下载…

Java:你还在想着考虑使用 tess4j 做文字识别吗?给你看看我的一点实践

需求&#xff1a;删除带有图片水印的图片 语言也设置为中文了&#xff0c;最后给我识别的文字是这样的 | AT V ! w{)" . ) ,/ R Ko 87 ’ 我能理解&#xff0c;毕竟图片很大张&#xff0c;不过不用担心&#xff0c;因为这个水印很有规律&#xff0c;就在右下方裁剪出宽 1…

基于单片机的智能燃气灶控制系统设计

摘要&#xff1a;针对传统燃气灶存在不能防干烧、不能进行温度检测、不能进行火力自动调节等问题&#xff0c;设计了一种基于单片机控制的智能燃气灶&#xff0c;它通过单片机进行控制&#xff0c;由开关模块、测温模块、语音播报模块、火力控制模块和防空烧模块五个模块组成&a…