1小时构建Vue3知识体系-Vue的响应式,让数据动起来

本文转载自:https://fangcaicoding.cn/course/12/62

大家好!我是方才,目前是8人后端研发团队的负责人,拥有6年后端经验&3年团队管理经验

系统学习践行者!近期在系统化输出前端入门相关技术文章,期望能帮大家构建一个完整的知识体系。

如果对你有所帮助,记得一键三连!

我创建了一个编程学习交流群(扫码关注后即可加入),秉持“一群人可以走得更远”的理念,期待与你一起 From Zero To Hero!

茫茫人海,遇见即是缘分!方才兄送你ElasticSearch系列知识图谱、前端入门系列知识图谱、系统架构师备考资料!

Vue的响应式,让数据动起来

Holle!大家好,我是方才兄,接着刚刚新建的vue项目,我们一起开始学习vue3的响应式。整体内容如下:

image-20241111220745002

重置下demo项目

为了方便后续的知识点学习,我们把一些不需要的内容先全部删除掉,包括style.cssHellowWord.vue等等文件。只保留必要的内容:

image-20241111221248451

同时将App.vue的内容重置为一个空的单文件组件:

<!--负责 HTML 结构的部分,所有展示的内容都在这里定义。-->
<template></template><!--逻辑的“后台”,数据、方法和生命周期钩子全在这里,`JavaScript`的代码就编写在这个标签下。-->
<script setup></script><!--用``CSS``定义组件样式,加上``scoped``后样式只会在这个组件内生效,不会影响别的地方。-->
<style scoped></style>

index.html的内容也可以修正下:

<!doctype html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>方才coding</title></head><body><div id="app"></div><script type="module" src="./src/main.js"></script></body>
</html>

重新运行vue3项目:

image-20241111221532574

image-20241111221622596

插值表达式-取值

接下来,我们将直接编写App.vue的内容,来学习响应式数据。

要让数据和页面互动起来,Vue 给我们提供了插值表达式。简单来说,就是在 HTML 中插入{{ }}双大括号,把变量展示出来。

场景示例:比如,想在页面上展示网站名称,我们可以这样写:

  <h1>欢迎来到:{{webName}}</h1>

只要给webName一个值,页面就会实时更新。如果网站名字从“方才”变成“方才coding“,这个变化会立刻反映到页面上。不用手动更新 DOM,Vue 会自动帮我们完成。那如何赋值呢?

基础响应式

接下来,是 Vue 响应式的两位主角——ref()reactive()。它们能让你的数据在变动时自动更新视图,具体选哪个,还得看你的数据结构。

ref():让数据成为响应式

我们可以先通过ref()来动态传值:

<!--负责 HTML 结构的部分,所有展示的内容都在这里定义。-->
<template><h1>欢迎来到:{{ webName }}</h1>
</template><!--逻辑的“后台”,数据、方法和生命周期钩子全在这里,`JavaScript`的代码就编写在这个标签下。-->
<script setup>
import {ref} from "vue";const webName = ref("方才coding")
</script><!--``CSS``定义组件样式,加上``scoped``后样式只会在这个组件内生效,不会影响别的地方。-->
<style scoped>
h1 {color: goldenrod;
}</style>

image-20241111222458936

结合之前学习的JavaScript,我们增加一个按钮,来改变变量webName的值,让数据动起来看看效果:

<!--负责 HTML 结构的部分,所有展示的内容都在这里定义。-->
<template><h1>欢迎来到:{{ webName }}</h1><button @click="randomName">加随机数</button>
</template><!--逻辑的“后台”,数据、方法和生命周期钩子全在这里,`JavaScript`的代码就编写在这个标签下。-->
<script setup>
import {ref} from "vue";const webName = ref("方才coding")const randomName = () => {webName.value = "方才coding +" + Math.random();
}
</script><!--用``CSS``定义组件样式,加上``scoped``后样式只会在这个组件内生效,不会影响别的地方。-->
<style scoped>
h1 {color: goldenrod;
}
</style>

image-20241111222847027

注意点:

  • ref()提供的变量,在script标签的代码中的函数使用,需要通过xxx.value的形式进行访问;
  • template标签中访问,使用插值表达式,直接使用变量即可,因为 <script setup>中的setup 会自动解包。

reactive():让对象成为响应式

另一种声明响应式状态的方式,即使用 reactive() API。与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性:

const webInfo = reactive({name: "方才coding2",author:"方才"
})

使用reactive包装对象,然后直接修改对象的属性,页面就会自动更新。完整的代码示例:

<!--负责 HTML 结构的部分,所有展示的内容都在这里定义。-->
<template><h1>欢迎来到:{{ webName }}</h1><button @click="randomName">加随机数</button><h2>欢迎来到:{{ webInfo.name }}</h2><h3>作者:{{ webInfo.author }}</h3>
</template><!--逻辑的“后台”,数据、方法和生命周期钩子全在这里,`JavaScript`的代码就编写在这个标签下。-->
<script setup>
import {reactive, ref} from "vue";const webName = ref("方才coding")const webInfo = reactive({name: "方才coding2",author:"方才"
})
const randomName = () => {webName.value = "方才coding +" + Math.random();webInfo.name = "方才coding2 +" + Math.random();
}
</script><!--用``CSS``定义组件样式,加上``scoped``后样式只会在这个组件内生效,不会影响别的地方。-->
<style scoped>
h1 {color: goldenrod;
}
</style>

image-20241111224457230

两者的区别

通过上面的demo,我们发现ref()reactive()都可以做到响应式更新数据的效果。那两者有什么区别呢?方才兄这里针对使用层面做一些简单的总结,供大家参考(官方更建议使用 ref() 作为声明响应式状态的主要 API):

对比项ref()reactive()
支持的数据类型可以持有任何类型的值,包括原始类型、深层嵌套的对象、数组或者 JavaScript 内置的数据结构只能用于对象类型 (对象、数组和如 MapSet 这样的集合类型)。它不能持有如 stringnumberboolean 这样的原始类型。
值修改当持有的是对象类型时,可以直接替换整个对象。不能替换整个对象,当使用let修饰时,替换整个对象,会导致与第一个引用的响应性连接的丢失。

简单通过代码演示下区别点:

  • 数据类型:

image-20241111230941237

image-20241111231045482

  • 值修改:

    const webInfoRef = ref({name: "方才coding-ref",author:"方才"
    })
    // 只能使用 let 修饰符,因为在下面的方法中会导致引用值的改变
    let webInfo = reactive({name: "方才coding-reactive",author:"方才"
    })const randomName = () => {webInfoRef.value = {name:"randomName 替换了"  + Math.random()}webInfo = {name:"randomName 替换了" + Math.random()};webInfo.author = "randomName" + Math.random()
    }
    

计算属性:节省计算资源的小帮手

当一个数据依赖于另一个数据时,你可以考虑用computed()。它能把计算逻辑集中在一起,提高代码的可读性,并且只有当依赖的数据发生变化时才重新计算。

场景示例const userCtTotal = computed(() => webInfo.userCt + webInfoRef.value.userCt)当依赖的数据发生变化时就会重新计算。

<!--负责 HTML 结构的部分,所有展示的内容都在这里定义。-->
<template><h1>ref()</h1><h2>欢迎来到:{{ webInfoRef.name }}</h2><h3>作者:{{ webInfoRef.author }}</h3><h3>userCt:{{ webInfoRef.userCt }}</h3><button @click="randomRef">testRef</button><h1>reactive</h1><h2>欢迎来到:{{ webInfo.name }}</h2><h3>作者:{{ webInfo.author }}</h3><button @click="testReactive">testReactive</button><p>用户总数{{ userCtTotal }}</p>
</template><!--逻辑的“后台”,数据、方法和生命周期钩子全在这里,`JavaScript`的代码就编写在这个标签下。-->
<script setup>
import {computed, reactive, ref} from "vue";const webInfoRef = ref({name: "方才coding-ref",author: "方才",userCt: 12
})
// 只能使用let修饰符,因为在下面的方法中会导致引用值的改变
let webInfo = reactive({name: "方才coding-reactive",author: "方才",userCt: 13
})const randomRef = () => {webInfoRef.value = {name: "randomRef 替换了" + Math.random()}webInfoRef.value.userCt = Math.ceil(Math.random() * 10);
}const testReactive = () => {webInfo.name = "testReactive 替换了" + Math.random()webInfo.userCt = Math.ceil(Math.random() * 10);
}const userCtTotal = computed(() => webInfo.userCt + webInfoRef.value.userCt)</script><!--``CSS``定义组件样式,加上``scoped``后样式只会在这个组件内生效,不会影响别的地方。-->
<style scoped>
h1 {color: goldenrod;
}</style>

image-20241111232433193

侦听器:灵活应对数据变化

虽然 Vue 能自动追踪大部分数据变动,但当你需要在数据变化时执行一些特定逻辑,比如发起请求、写入日志,就可以用watch()来实现。

场景示例:比如想在用户总数发生变更时,做一个弹窗提醒:

watch(// 第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组;userCtTotal,// 回调函数,默认提供变化前后的参数(newValue,oldValue)=>{let msg = `用户总数变化啦!变化前:【${oldValue}】,变化后:【${newValue}`;alert(msg)}
)

每当userCtTotal的值变化时,watch都会触发,帮你执行相关的逻辑。

image-20241111233221939

倾听器有3个参数:

watch(// 第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组;userCtTotal,// 第一个参数是回调函数,默认提供变化前后的参数(newValue, oldValue) => {let msg = `用户总数变化啦!变化前:【${oldValue}】,变化后:【${newValue}】`;alert(msg)},// 第三个参数是可选配置:三个可选配置{immediate: true, deep: true, once: true}
)

可选配置说明:

  • immediatewatch 默认是懒执行的:仅当数据源变化时,才会执行回调。希望在创建侦听器时,立即执行一遍回调,可以通过传入 immediate: true 选项来强制侦听器的回调立即执行,默认为false;
  • deep 参数:(默认值)表示仅监视对象的顶层属性的变化,deep: true 则表示递归监视对象所有嵌套属性的变化;
  • once:每当被侦听源发生变化时,侦听器的回调就会执行。如果希望回调只在源变化时触发一次,请使用 once: true 选项,默认为false。

仅了解:只读和浅响应式

虽然上面几种已经能满足很多场景需求,但 Vue 还为我们提供了更深入的优化手段。

readonlyshallowReadonly:只读保护数据

当你希望一个数据不被更改时,可以使用readonly()或者shallowReadonly()。前者是完全只读,后者只针对对象的外层属性。这样可以避免一些误操作导致数据污染。

import { readonly, shallowReadonly } from 'vue';const readOnlyUser = readonly({ name: '方才兄' });
const shallowReadOnlyUser = shallowReadonly({ name: '方才兄' });

用这两个方法创建的数据,开发中就不用担心它会被误改,非常适合做常量配置等数据。

shallowRefshallowReactive:浅层响应提升性能

Vue 默认是深层响应式,但有时只需要外层响应,这时候shallowRefshallowReactive就是理想选择。它们只追踪对象的第一层属性,内部属性不会响应式更新,可以优化性能。

场景示例:比如管理一大批用户信息,但并不关心用户的每一项详细信息。

import { shallowReactive } from 'vue';const users = shallowReactive([{ name: '方才兄', age: 28 }, { name: '小明', age: 24 }]);users.push({ name: '小红', age: 21 }); // 新增的用户会触发响应,但不会追踪每个用户的详细变化

使用浅层响应性,节省了大量性能开销,适合大量数据和不频繁更新的场景。

结语

掌握了 Vue 的响应式,你在数据和视图之间就如鱼得水,开发起来畅通无阻。记得多动手实践,用ref()reactive()实现基本功能,再通过computedwatch优化逻辑。更高级的功能如readonly和浅响应式,可以根据场景选择。关注方才兄,带你 Vue 路上从入门到进阶,代码效率飞起!—

近期更新计划

近期更新计划(有需要的小伙伴,记得点赞关注哟!)

  1. 输出vue、router、elementplus等前端框架技术文章,期望能帮助大家快速建立相关的知识体系;
  2. 基于vue3+springboot3的前后端分离的博客系统已经开源啦,欢迎大家star!https://gitee.com/fangcaicoding/fangcai-coding-blog

“学编程,一定要系统化”——若你也是系统学习的践行者,记得点赞关注,期待与你一起 From Zero To Hero!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Docker网络详解

安装Docker时&#xff0c;它会自动创建三个网络&#xff0c;bridge&#xff08;创建容器默认连接到此网络&#xff09;、 none 、host 网络模式简介Host容器将不会虚拟出自己的网卡&#xff0c;配置自己的IP等&#xff0c;而是使用宿主机的IP和端口。Bridge此模式会为每一个容…

宝塔面板部署前端项目(包含ssl证书部署)

环境&#xff1a; ①nginx&#xff08;这里使用的版本为1.21.41&#xff09; ②前端项目文件&#xff08;以根目录打包的文件&#xff09; ③域名 ④SLL数字证书的key文件和.pem文件&#xff08;我们这里用的是nginx部署&#xff0c;因此下载证书的时候&#xff0c;下载nginx对…

【区别】ONLYOFFICE心得体会,8.2与8.1区别

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

Equity-Transformer:求解NP-Hard Min-Max路由问题的顺序生成算法(AAAI-24)(未完)

文章目录 AbstractIntroduction问题表述MethodologyAbstract 最小最大路由问题旨在通过智能体合作完成任务来最小化多个智能体中最长行程的长度。这些问题包括对现实世界有重大影响的应用场景,但已知属于NP-hard问题。现有方法在大规模问题上面临挑战,尤其是在需要协调大量智…

ScrumMaster认证机构及CSM、PSM、RSM价值解析

近十年Scrum在国内备受关注&#xff0c;成为一种最流行的现代敏捷工作方式。ScrumMaster这一独特的角色&#xff0c;在企业内部推动Scrum落地的过程中越来越重要。各种ScrumMaster认证课程也蜂拥而至&#xff0c;甚至鱼目混珠。 我们为大家梳理了目前市面上出现的ScrumMaster认…

HLS实现图像二值化

最近在学习HLS语言&#xff0c;所以就自己摸索尝试了用HLS实现了图像二值化&#xff0c;把这个内容总结一下&#xff0c;分享出来。 首先打开HLS&#xff0c;然后新建一个Project&#xff0c;之后再在Source栏点击右键&#xff0c;选择New File...&#xff0c;创建名为pixelBi…

[ 内网渗透实战篇-1 ] 单域环境搭建与安装域环境判断域控定位CS插件装载CS上线

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

通过物流分拣系统来理解RabbitMQ的消息机制

RabbitMQ作为一个消息中间件&#xff0c;通过队列和路由机制&#xff0c;帮助应用程序高效传递消息。而它的消息流转过程&#xff0c;其实可以用物流分拣系统来直观理解。 在一个典型的物流分拣系统中&#xff0c;包裹会经过多个节点&#xff08;比如分拣中心、配送站&#xf…

别再乱搜了 这 5个宝藏AE模板网站,小白也能做出大片级动画

Hello&#xff0c;大家好&#xff0c;我是后期圈&#xff01; 今天来聊聊一个后期人都绕不开的话题&#xff1a;AE模板网站&#xff01;模板可是后期人的福音&#xff0c;无论你是想要惊艳的开场动画&#xff0c;酷炫的转场效果&#xff0c;还是个性化的文字特效&#xff0c;一…

CSS 编写位置详解及优先级分析

在前端开发中,CSS 的编写位置对项目的组织结构和维护性至关重要。不同的编写位置不仅影响代码的可读性和复用性,还决定了样式应用的优先级。 本文将根据编写位置的不同,详细介绍其定义、使用场景和优先级。 行内样式(Inline Styles) 行内样式(又称:内联样式)是将 CS…

ChatGPT 搜索 vs Google 搜索

原文&#xff1a;Amanda Caswell - 2024.11.01 随着 OpenAI 推出的实时搜索功能&#xff0c;ChatGPT 正在逐步成为像 Google 这样的传统搜索引擎的竞争对手。ChatGPT 以其对话式的回答方式而闻名&#xff0c;它能够在没有广告干扰的情况下提供实时的上下文信息。 我迫不及待地…

多进程的操作和案例

文章目录 高效编程一、多任务原理二、进程1、概念2、使用进程3、全局变量在多个子进程中不能共享4、启动大量子进程5、map方法6、单进程与多进程复制文件对比7、进程间通信8、进程实现生产者消费者9、案例&#xff08;抓取斗图&#xff09; 高效编程 一、多任务原理 概念 现代…

【更新中】《硬件架构的艺术》笔记(二):时钟与复位

本章主要针对ASIC设计给出建议&#xff0c;独立于CAD工具以及工艺&#xff0c;主要针对模块设计和存储器接口。 同步设计 这是对时钟域控制最安全的方法&#xff0c;单个主时钟和单个主置位/复位信号驱动设计中所有时序器件。 避免使用行波计数器 行波计数器&#xff1a;用…

Spring Boot编程训练系统:架构设计与技术选型

3系统分析 3.1可行性分析 通过对本编程训练系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本编程训练系统采用SSM框架&#xff0c;JAVA作为开发语言&#…

DAY111PHP开发框架THIKNPHP反序列化POP利用链RCE执行文件删除

一、文件删除利用链分析 1、__destruct发现调用$this->removeFiles(); 2、removeFiles();函数方法file_exists&#xff0c;unlink($filename);文件删除功能 3、unserialize(base64_decode($_GET[id])); 有可控变量 4、pop文件删除利用链的使用 只有在这个类中调用 Files可…

如何使用亿图脑图MindMaster大纲功能

亿图脑图MindMaster作为一款出色的思维导图软件&#xff0c;具备丰富的编辑和展示功能。就拿大纲模式而言&#xff0c;用户可以清晰地浏览思维导图上的内容。因为大纲功能可以将思维导图上的内容以文档归纳的形式呈现出来&#xff0c;便于用户分类记忆。 自由切换思维导图模式…

Python的Eval函数执行结果和Lua脚本中LuaFunction的执行结果有何异同

最近在维护一个项目的时候&#xff0c;同时用到了Python和Lua两种脚本语言&#xff0c;发现很多有意思的东西&#xff0c;比如Python的Eval函数和Lua的LuaFunction函数&#xff0c;他们都是返回目标函数的句柄&#xff0c;那么在用法和机制上又有什么不同呢&#xff1f;为了全面…

DQN强化训练agent玩是男人就下xx层小游戏

游戏代码参考Python是男人就下一百层小游戏源代码_是男人就下一百层完整代码python-CSDN博客 在游戏作者代码基础上修改了下使该游戏在失败后能自动重新开始&#xff0c;方便后续能不间断训练 def reset_game(self):self.score 0self.end Falseself.last 6 * SIDEself.dire …

2024最新版JavaScript逆向爬虫教程-------基础篇之面向对象

目录 一、概念二、对象的创建和操作 2.1 JavaScript创建对象的方式2.2 对象属性操作的控制2.3 理解JavaScript创建对象 2.3.1 工厂模式2.3.2 构造函数2.3.3 原型构造函数 三、继承 3.1 通过原型链实现继承3.2 借用构造函数实现继承3.3 寄生组合式继承 3.3.1 对象的原型式继承…

网络编程示例之网络socket程序编程

注意&#xff1a;学习资料可在ElfBoard官方网站“资料”专区获取。 本节用到的源码路径&#xff1a;ELF 1开发板资料包->03-例程源码->03-1 命令行例程源码->05_elf1_cmd_net tcp协议程序 tcp_server.c 服务端仍然是按照如下顺序进行编写&#xff1a; socket()//创…