【Vue篇】数据秘语:从watch源码看响应式宇宙的蝴蝶效应

目录

引言

一、watch侦听器(监视器)

1.作用:

2.语法:

3.侦听器代码准备

4. 配置项

 5.总结

二、翻译案例-代码实现

1.需求

2.代码实现

三、综合案例——购物车案例

1. 需求 

 2. 代码


引言

💬 欢迎讨论:关于Vue侦听器应用、防抖优化与响应式设计,欢迎评论区交流技术细节!
👍 点赞支持:若本文助你攻克watch难题,欢迎三连助力,共享前端技术精粹!
🚀 进阶指南:watch与计算属性联奏,演绎Vue响应式交响曲,构建数据与视图的动态协奏。

一、watch侦听器(监视器)

1.作用:

​ 监视数据变化,执行一些业务逻辑或异步操作

2.语法:

  1. watch同样声明在跟data同级的配置项中

  2. 简单写法: 简单类型数据直接监视

  3. 完整写法:添加额外配置项

 

3. 配置项

完整写法 —>添加额外的配置项

  1. deep:true 对复杂类型进行深度监听
  2. immdiate:true 初始化 立刻执行一次
data: {obj: {words: '苹果',lang: 'italy'},
},watch: {// watch 完整写法对象: {deep: true, // 深度监视immdiate:true,//立即执行handler函数handler (newValue) {console.log(newValue)}}
}

 4.总结

watch侦听器的写法有几种?

1.简单写法

2.完整写法

二、翻译案例-代码实现

1.需求

  • 当文本框输入的时候 右侧翻译内容要时时变化(实时翻译
  • 当下拉框中的语言发生变化的时候 右侧翻译的内容依然要时时变化
  • 如果文本框中有默认值的话要立即翻译

2.代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-size: 18px;}#app {padding: 10px 20px;}.query {margin: 10px 0;}.box {display: flex;}textarea {width: 300px;height: 160px;font-size: 18px;border: 1px solid #dedede;outline: none;resize: none;padding: 10px;}textarea:hover {border: 1px solid #1589f5;}.transbox {width: 300px;height: 160px;background-color: #f0f0f0;padding: 10px;border: none;}.tip-box {width: 300px;height: 25px;line-height: 25px;display: flex;}.tip-box span {flex: 1;text-align: center;}.query span {font-size: 18px;}.input-wrap {position: relative;}.input-wrap span {position: absolute;right: 15px;bottom: 15px;font-size: 12px;}.input-wrap i {font-size: 20px;font-style: normal;}</style></head><body><div id="app"><!-- 条件选择框 --><div class="query"><span>翻译成的语言:</span><select v-model="obj.lang"><option value="italy">意大利</option><option value="english">英语</option><option value="german">德语</option></select></div><!-- 翻译框 --><div class="box"><div class="input-wrap"><textarea v-model="obj.words"></textarea><span><i>⌨️</i>文档翻译</span></div><div class="output-wrap"><div class="transbox">{{ result }}</div></div></div></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>// 需求:输入内容,修改语言,都实时翻译// 接口地址:https://applet-base-api-t.itheima.net/api/translate// 请求方式:get// 请求参数:// (1)words:需要被翻译的文本(必传)// (2)lang: 需要被翻译成的语言(可选)默认值-意大利// -----------------------------------------------const app = new Vue({el: '#app',data: {obj: {words: '小黑',lang: 'italy'},result: '', // 翻译结果},watch: {obj: {deep: true, // 深度监视immediate: true, // 立刻执行,一进入页面handler就立刻执行一次handler (newValue) {clearTimeout(this.timer)this.timer = setTimeout(async () => {const res = await axios({url: 'https://applet-base-api-t.itheima.net/api/translate',params: newValue})this.result = res.data.dataconsole.log(res.data.data)}, 300)}}// 'obj.words' (newValue) {//   clearTimeout(this.timer)//   this.timer = setTimeout(async () => {//     const res = await axios({//       url: 'https://applet-base-api-t.itheima.net/api/translate',//       params: {//         words: newValue//       }//     })//     this.result = res.data.data//     console.log(res.data.data)//   }, 300)// }}})</script></body>
</html>

三、综合案例——购物车案例

1. 需求 

需求说明:

  1. 渲染功能
  2. 删除功能
  3. 修改个数
  4. 全选反选
  5. 统计 选中的 总价 和 总数量
  6. 持久化到本地

实现思路:

1.基本渲染: v-for遍历、:class动态绑定样式

2.删除功能 : v-on 绑定事件,获取当前行的id

3.修改个数 : v-on绑定事件,获取当前行的id,进行筛选出对应的项然后增加或减少

4.全选反选

  1. 必须所有的小选框都选中,全选按钮才选中 → every
  2. 如果全选按钮选中,则所有小选框都选中
  3. 如果全选取消,则所有小选框都取消选中

声明计算属性,判断数组中的每一个checked属性的值,看是否需要全部选

5.统计 选中的 总价 和 总数量 :通过计算属性来计算选中的总价和总数量

6.持久化到本地: 在数据变化时都要更新下本地存储 watch

 2. 代码

css 

.app-container {padding-bottom: 300px;width: 800px;margin: 0 auto;
}
@media screen and (max-width: 800px) {.app-container {width: 600px;}
}
.app-container .banner-box {border-radius: 20px;overflow: hidden;margin-bottom: 10px;
}
.app-container .banner-box img {width: 100%;
}
.app-container .nav-box {background: #ddedec;height: 60px;border-radius: 10px;padding-left: 20px;display: flex;align-items: center;
}
.app-container .nav-box .my-nav {display: inline-block;background: #5fca71;border-radius: 5px;width: 90px;height: 35px;color: white;text-align: center;line-height: 35px;margin-right: 10px;
}.breadcrumb {font-size: 16px;color: gray;
}
.table {width: 100%;text-align: left;border-radius: 2px 2px 0 0;border-collapse: separate;border-spacing: 0;
}
.th {color: rgba(0, 0, 0, 0.85);font-weight: 500;text-align: left;background: #fafafa;border-bottom: 1px solid #f0f0f0;transition: background 0.3s ease;
}
.th.num-th {flex: 1.5;
}
.th {text-align: center;
}
.th:nth-child(4),
.th:nth-child(5),
.th:nth-child(6),
.th:nth-child(7) {text-align: center;
}
.th.th-pic {flex: 1.3;
}
.th:nth-child(6) {flex: 1.3;
}.th,
.td {position: relative;padding: 16px 16px;overflow-wrap: break-word;flex: 1;
}
.pick-td {font-size: 14px;
}
.main,
.empty {border: 1px solid #f0f0f0;margin-top: 10px;
}
.tr {display: flex;cursor: pointer;border-bottom: 1px solid #ebeef5;
}
.tr.active {background-color: #f5f7fa;
}
.td {display: flex;justify-content: center;align-items: center;
}.table img {width: 100px;height: 100px;
}button {outline: 0;box-shadow: none;color: #fff;background: #d9363e;border-color: #d9363e;color: #fff;background: #d9363e;border-color: #d9363e;line-height: 1.5715;position: relative;display: inline-block;font-weight: 400;white-space: nowrap;text-align: center;background-image: none;border: 1px solid transparent;box-shadow: 0 2px 0 rgb(0 0 0 / 2%);cursor: pointer;transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;touch-action: manipulation;height: 32px;padding: 4px 15px;font-size: 14px;border-radius: 2px;
}
button.pay {background-color: #3f85ed;margin-left: 20px;
}.bottom {height: 60px;display: flex;align-items: center;justify-content: space-between;padding-right: 20px;border: 1px solid #f0f0f0;border-top: none;padding-left: 20px;
}
.right-box {display: flex;align-items: center;
}
.check-all {cursor: pointer;
}
.price {color: hotpink;font-size: 30px;font-weight: 700;
}
.price-box {display: flex;align-items: center;
}
.empty {padding: 20px;text-align: center;font-size: 30px;color: #909399;
}
.my-input-number {display: flex;
}
.my-input-number button {height: 40px;color: #333;border: 1px solid #dcdfe6;background-color: #f5f7fa;
}
.my-input-number button:disabled {cursor: not-allowed!important;
}
.my-input-number .my-input__inner {height: 40px;width: 50px;padding: 0;border: none;border-top: 1px solid #dcdfe6;border-bottom: 1px solid #dcdfe6;
}

html 

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><link rel="stylesheet" href="./css/inputnumber.css" /><link rel="stylesheet" href="./css/index.css" /><title>购物车</title></head><body><div class="app-container" id="app"><!-- 顶部banner --><div class="banner-box"><img src="http://autumnfish.cn/static/fruit.jpg" alt="" /></div><!-- 面包屑 --><div class="breadcrumb"><span>🏠</span>/<span>购物车</span></div><!-- 购物车主体 --><div class="main" v-if="fruitList.length > 0"><div class="table"><!-- 头部 --><div class="thead"><div class="tr"><div class="th">选中</div><div class="th th-pic">图片</div><div class="th">单价</div><div class="th num-th">个数</div><div class="th">小计</div><div class="th">操作</div></div></div><!-- 身体 --><div class="tbody"><div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }"><div class="td"><input type="checkbox" v-model="item.isChecked" /></div><div class="td"><img :src="item.icon" alt="" /></div><div class="td">{{ item.price }}</div><div class="td"><div class="my-input-number"><button :disabled="item.num <= 1" class="decrease" @click="sub(item.id)"> - </button><span class="my-input__inner">{{ item.num }}</span><button class="increase" @click="add(item.id)"> + </button></div></div><div class="td">{{ item.num * item.price }}</div><div class="td"><button @click="del(item.id)">删除</button></div></div></div></div><!-- 底部 --><div class="bottom"><!-- 全选 --><label class="check-all"><input type="checkbox" v-model="isAll"/>全选</label><div class="right-box"><!-- 所有商品总价 --><span class="price-box">总价&nbsp;&nbsp;:&nbsp;&nbsp;¥&nbsp;<span class="price">{{ totalPrice }}</span></span><!-- 结算按钮 --><button class="pay">结算( {{ totalCount }} )</button></div></div></div><!-- 空车 --><div class="empty" v-else>🛒空空如也</div></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const defaultArr = [{id: 1,icon: 'http://autumnfish.cn/static/火龙果.png',isChecked: true,num: 2,price: 6,},{id: 2,icon: 'http://autumnfish.cn/static/荔枝.png',isChecked: false,num: 7,price: 20,},{id: 3,icon: 'http://autumnfish.cn/static/榴莲.png',isChecked: false,num: 3,price: 40,},{id: 4,icon: 'http://autumnfish.cn/static/鸭梨.png',isChecked: true,num: 10,price: 3,},{id: 5,icon: 'http://autumnfish.cn/static/樱桃.png',isChecked: false,num: 20,price: 34,},]const app = new Vue({el: '#app',data: {// 水果列表fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr,},computed: {// 默认计算属性:只能获取不能设置,要设置需要写完整写法// isAll () {//   // 必须所有的小选框都选中,全选按钮才选中 → every//   return this.fruitList.every(item => item.isChecked)// }// 完整写法 = get + setisAll: {get () {return this.fruitList.every(item => item.isChecked)},set (value) {// 基于拿到的布尔值,要让所有的小选框 同步状态this.fruitList.forEach(item => item.isChecked = value)}},// 统计选中的总数 reducetotalCount () {return this.fruitList.reduce((sum, item) => {if (item.isChecked) {// 选中 → 需要累加return sum + item.num} else {// 没选中 → 不需要累加return sum}}, 0)},// 总计选中的总价 num * pricetotalPrice () {return this.fruitList.reduce((sum, item) => {if (item.isChecked) {return sum + item.num * item.price} else {return sum}}, 0)}},methods: {del (id) {this.fruitList = this.fruitList.filter(item => item.id !== id)},add (id) {// 1. 根据 id 找到数组中的对应项 → findconst fruit = this.fruitList.find(item => item.id === id)// 2. 操作 num 数量fruit.num++},sub (id) {// 1. 根据 id 找到数组中的对应项 → findconst fruit = this.fruitList.find(item => item.id === id)// 2. 操作 num 数量fruit.num--}},watch: {fruitList: {deep: true,handler (newValue) {// 需要将变化后的 newValue 存入本地 (转JSON)localStorage.setItem('list', JSON.stringify(newValue))}}}})</script></body>
</html>

以上就是关于【Vue篇】数据秘语:从watch源码看响应式宇宙的蝴蝶效应  内容啦。本文 剖析了watch的监听机制、深度追踪技巧,并通过翻译防抖与购物车案例实战,解构了数据与视图的动态绑定逻辑。若对watch配置、计算属性联用或本地持久化方案存在疑问,欢迎评论区留下技术火花!💡

 

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

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

相关文章

WPS中代码段的识别方法及JS宏实现

在WPS中&#xff0c;文档的基本结构可以通过对象模型来理解&#xff1a; &#xff08;1&#xff09;Document对象&#xff1a;表示整个文档 &#xff08;2&#xff09;Range对象&#xff1a;表示文档中的一段连续区域&#xff0c;可以是一个字符、一个句子或整个文档 &#…

el-tree结合el-tree-transfer实现穿梭框里展示树形数据

参考文章&#xff1a;我把他的弹框单拉出来一个独立文件作为组件方便使用&#xff0c;遇到一些问题记录一下。 testComponet.vue <template><div class"per_container"><div class"per_con_left"><div class"per_con_title&q…

Go 后端中双 token 的实现模板

下面是一个典型的 Go 后端双 Token 认证机制 实现模板&#xff0c;使用 Gin 框架 JWT Redis&#xff0c;结构清晰、可拓展&#xff0c;适合实战开发。 项目结构建议 /utils├── jwt.go // Access & Refresh token 的生成和解析├── claims.go // 从请求…

Typescript学习教程,从入门到精通,TypeScript 对象语法知识点及案例代码(7)

TypeScript 对象语法知识点及案例代码 TypeScript 是 JavaScript 的超集&#xff0c;提供了静态类型检查和其他增强功能。在 TypeScript 中&#xff0c;对象是面向对象编程&#xff08;OOP&#xff09;的基础。 一、对象概述 在 TypeScript 中&#xff0c;对象是属性的集合&a…

应用BERT-GCN跨模态情绪分析:贸易缓和与金价波动的AI归因

本文运用AI量化分析框架&#xff0c;结合市场情绪因子、宏观经济指标及技术面信号&#xff0c;对黄金与美元指数的联动关系进行解析&#xff0c;揭示本轮贵金属回调的深层驱动因素。 周三&#xff0c;现货黄金价格单日跌幅达2.1%&#xff0c;盘中触及3167.94美元/盎司关键价位&…

命令行登录 MySQL 报 Segmentation fault 故障解决

问题描述&#xff1a;对 mysql8.0.35 源码进行 make&#xff0c;由于一开始因为yum源问题少安装依赖库 库&#xff0c;在链接时遇到错误 undefined reference to&#xff0c;后来安装了相关依赖库&#xff0c;再次 make 成功。于是将 mysqld 启动&#xff0c;再用 mysql -u roo…

Axure设计数字乡村可视化大屏:构建乡村数据全景图

今天&#xff0c;让我们一同深入了解由Axure设计的数字乡村可视化大屏&#xff0c;看看它如何通过精心的布局和多样化的图表类型&#xff0c;将乡村的各类数据以直观、易懂的方式呈现出来&#xff0c;为乡村管理者提供有力的数据支持。 原型效果预览链接&#xff1a;Axure数字乡…

3D个人简历网站 4.小岛

1.模型素材 在Sketchfab上下载狐狸岛模型&#xff0c;然后转换为素材资源asset&#xff0c;嫌麻烦直接在网盘链接下载素材&#xff0c; Fox’s islandshttps://sketchfab.com/3d-models/foxs-islands-163b68e09fcc47618450150be7785907https://gltf.pmnd.rs/ 素材夸克网盘&a…

智能开发工具PhpStorm v2025.1——增强AI辅助编码功能

PhpStorm是一个轻量级且便捷的PHP IDE&#xff0c;其旨在提高用户效率&#xff0c;可深刻理解用户的编码&#xff0c;提供智能代码补全&#xff0c;快速导航以及即时错误检查。可随时帮助用户对其编码进行调整&#xff0c;运行单元测试或者提供可视化debug功能。 立即获取PhpS…

Spark 的运行模式(--master) 和 部署方式(--deploy-mode)

Spark 的 运行模式&#xff08;--master&#xff09; 和 部署方式&#xff08;--deploy-mode&#xff09;&#xff0c;两者的核心区别在于 资源调度范围 和 Driver 进程的位置。 一、核心概念对比 维度--master&#xff08;运行模式&#xff09;--deploy-mode&#xff08;部署…

sqli—labs第八关——布尔盲注

一&#xff1a;确定注入类型 按照我们之前的步骤来 输入 ?id1 and 11-- ?id1 and 12-- 界面正常 第二行界面异常空白 所以注入类型为单引号闭合型 二&#xff1a; 布尔盲注 1.判断是否使用条件 &#xff08;1&#xff09;&#xff1a;存在注入但不会直接显示查询结果 …

ARP 原理总结

&#x1f310; 一、ARP 原理总结 ARP&#xff08;Address Resolution Protocol&#xff09;是用于通过 IP 地址解析 MAC 地址的协议&#xff0c;工作在 链路层 与 网络层之间&#xff08;OSI 模型的第三层与第二层之间&#xff09;。 &#x1f501; ARP通信过程&#xff1a; …

SpringCloud——EureKa

目录 1.前言 1.微服务拆分及远程调用 3.EureKa注册中心 远程调用的问题 eureka原理 搭建EureKaServer 服务注册 服务发现 1.前言 分布式架构&#xff1a;根据业务功能对系统进行拆分&#xff0c;每个业务模块作为独立项目开发&#xff0c;称为服务。 优点&#xff1a; 降…

机顶盒刷机笔记

疑难杂症解决 hitool线刷网口不通tftp超时--》关闭防火墙cm201-2卡刷所有包提示失败abort install--》找个卡刷包只刷fastboot分区再卡刷就能通过了&#xff08;cm201救砖包 (M8273版子&#xff09;&#xff09; 刷机工具 海兔烧录工具HiTool-STB-5.3.12工具&#xff0c;需要…

Linux动静态库制作与原理

什么是库 库是写好的现有的&#xff0c;成熟的&#xff0c;可以复用的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个人的代码都从零开始&#xff0c;因此库的存在意义非同寻常。 本质上来说库是一种可执行代码的二进制形式&#xff0c;可以被操作系统…

如何通过小智AI制作会说话的机器人玩具?

一、硬件准备与组装 1. 核心硬件选择 主控芯片&#xff1a;选择支持无线网络连接、音频处理和可编程接口的嵌入式开发板 音频模块&#xff1a;配备拾音麦克风与小型扬声器&#xff0c;确保语音输入/输出功能 显示模块&#xff1a;选择适配的交互显示屏用于可视化反馈 扩展模…

如何控制邮件发送频率避免打扰用户

一、用户行为 监测用户与邮件的互动数据&#xff0c;如打开率、点击率下滑或退订申请增多&#xff0c;可能是发送频率过高的警示信号。利用邮件营销平台的分析工具&#xff0c;识别这些指标的变动趋势&#xff0c;为调整提供依据。 二、行业特性与受众差异 不同行业用户对邮…

定积分的“偶倍奇零”性质及其使用条件

定积分的“偶倍奇零”性质是针对对称区间上的奇偶函数积分的重要简化方法。以下是其核心内容和应用要点&#xff1a; ​一、基本性质 ​偶函数&#xff08;偶倍&#xff09;​ 若 f(x) 在 [−a,a] 上为偶函数&#xff08;即 f(−x)f(x)&#xff09;&#xff0c;则&#xff1a; …

如何在 Windows 11 或 10 上安装 Fliqlo 时钟屏保

了解如何在 Windows 11 或 10 上安装 Fliqlo,为您的 PC 或笔记本电脑屏幕添加一个翻转时钟屏保以显示时间。 Fliqlo 是一款适用于 Windows 和 macOS 平台的免费时钟屏保。它也适用于移动设备,但仅限于 iPhone 和 iPad。Fliqlo 的主要功能是在用户不活动时在 PC 或笔记本电脑…

【C/C++】C++并发编程:std::async与std::thread深度对比

文章目录 C并发编程&#xff1a;std::async与std::thread深度对比1 核心设计目的以及区别2 详细对比分析3 代码对比示例4 适用场景建议5 总结 C并发编程&#xff1a;std::async与std::thread深度对比 在 C 中&#xff0c;std::async 和 std::thread 都是用于并发编程的工具&am…