加载中...
实战1——添加账本数据
第1节:环境准备与项目创建
第2节:响应式基础
第3节:计算属性
第4节:侦听器
第5节:生命周期
第6节:组件基础
第7节:实战1——添加账本数据
第8节:实战2——完善小账本
第9节:实战3——Toast插件与项目打包
课文封面

布局样式部分可以直接从课文中获取,专心写逻辑部分即可。
数据最终会保存在本地缓存中,首页部分下节课完成,所以暂时数据存储成功,首页也不会渲染数据。

准备工作

经过前面的课文学习,我们已经掌握了一些vue3的基础知识,接下来让我们试着完成一个简单的账本App。
因为样式部分比较简单,所以将直接从逻辑代码部分开始讲解。课文中会提供静态资源以及布局代码,也可以直接从课堂作业(付费)中下载项目压缩包(逻辑部分未实现)。

  1. 创建项目

  2. 下载静态资源

  3. 将下载的静态资源放到创建的项目src目录下

  4. App.vue的代码替换

  5. 在components目录下创建addBillPopup.vue,并复制代码进去

目录结构如下,只有src目录下的文件有改动

未命名

项目介绍🎞️

任务目标👀

未命名

  1. 点击切换tab状态(支出/收入),并且根据当前选中的tab,渲染 出/src/utils/billingData.js下的标签,以及点击标签进行选中。
  2. 日期输入框默认值为"今天"。
  3. 点击右上角的"x"时关闭新增账单popup。
  4. 完成记一笔功能:在选择完类型、标签、日期、输入好金额后点击"记一笔"按钮时,将数据存到缓存(localStorage)中,"记一笔"之后关闭新增账单popup。

以上就是本节课中需要达成的目标,动手能力强的同学也可以尝试自己实现,实现方式可以不同,能达成目标就行。

视频🎞️

静态样式文件

App.vue

<script setup> import billList from "/src/components/billList.vue"; </script> <template> <!-- 顶部区域 --> <div class="header-box"> <div class="header"> <!-- bar --> <div class="header-top-bar"> <!-- 左占位 --> <div></div> <!-- 当前日期 --> <div class="date">08-01</div> <!-- 添加账单入口 --> <div class="add-ledger"> <img src="/src/assets/svg/add.svg" alt="" width="55" height="55" /> </div> </div> <div class="statistical-container"> <div> <div>月结余</div> <div class="balance">1</div> </div> <div> <span>月支出:0</span> <span>月收入:1</span> </div> </div> </div> </div> <!-- 预算卡片 --> <div class="progress-card"> <div class="space-between"> <span>本月预算</span> <!-- 编辑预算值入口 --> <img src="/src/assets/svg/more.svg" width="20" height="20" /> </div> <!-- 进度条 --> <div class="progress-bar"> <div class="progress-bar-active" :style="`width: ${100}%`"></div> </div> </div> <!-- 账单记录列表 --> <billList></billList> </template> <style scoped> .header-box { height: 189px; } .header { width: 100%; background: url("/src/assets/bg3.jpg") center; background-size: cover; color: #ffffff; font-size: 20px; position: fixed; height: 189px; top: 0; left: 0; z-index: 2; } .header-top-bar { display: flex; justify-content: space-between; align-items: center; height: 55px; } .header-top-bar > div { flex: 1; } .date { text-align: center; } .add-ledger { height: 55px; text-align: right; } .statistical-container { padding: 16px 24px; } .balance { margin-bottom: 10px; font-size: 28px; } .statistical-container span { margin-right: 20px; } .progress-card { width: 92%; padding: 12px; margin: 16px auto; background: #ffffff; box-sizing: border-box; border-radius: 10px; font-size: 15px; } .space-between { display: flex; align-items: center; justify-content: space-between; } .progress-bar { width: 100%; height: 12px; background: #dddddd; border-radius: 15px; margin: 10px 0; overflow: hidden; } .progress-bar-active { height: 100%; background: #58a595; border-radius: 15px; transition: width 0.5s; } </style>

addBillPopup.vue

<script setup> // ToDo // 1. 点击切换tab类型(支出/收入),并且根据当前选中的tab,渲染 // 出/src/utils/iconData.js下的标签,以及点击标签进行选中。 // 2. 日期输入框默认值为"今天"。 // 3. 点击右上角的x时关闭popup。 // 4. 完成记一笔功能,并且将记录的数据存到缓存(localStorage)中, // 记一笔之后关闭popup </script> <template> <div class="popup"> <div class="popup-box"> <div class="top-box"> <!-- tab类型切换 --> <div class="left-btn"> <div class="active"> 支出 </div> <div> 收入 </div> </div> <!-- 关闭按钮(不找图标了凑合下) --> <div class="close">x</div> </div> <!-- 账单tag列表 --> <div class="classification-box"> <div class="classification-item active"> <img src="/src/assets/svg/finance.svg" width="30" /> <div>理财</div> </div> </div> <div class="input-box"> <div> <span>日期:</span> <!-- 账单日期输入框 --> <input type="date" /> </div> <div> <span>金额:</span> <!-- 记账金额输入框 --> <input type="number" placeholder="请输入" /> </div> </div> <!-- 提交按钮 --> <button class="submit-btn">记一笔</button> </div> </div> </template> <style scoped> .popup { background: #f2f2f2; height: 95vh; z-index: 9; position: fixed; width: 100%; top: 0; } .popup-box { padding: 12px 12px 20px; box-sizing: border-box; background: white; } .close { font-size: 22px; line-height: 28px; width: 28px; height: 28px; text-align: center; } .top-box { display: flex; align-items: center; justify-content: space-between; margin: 0 0 15px; } .left-btn { width: 150px; border: 1px solid #cccccc; border-radius: 10px; overflow: hidden; } .left-btn > div:first-child { border-right: 1px solid #cccccc; } .left-btn > div { width: 49.5%; display: inline-block; text-align: center; height: 100%; padding: 5px 0; } .active { background: #dddddd; } .classification-box { display: flex; align-items: center; flex-wrap: wrap; } .classification-item { width: 25%; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 15px; padding: 4px 0; border-radius: 8px; transition: all 0.3s; } .input-box { width: 100%; padding: 0 15px; box-sizing: border-box; margin-top: 20px; } .input-box > div { white-space: nowrap; margin-bottom: 20px; } .input-box input { font-size: 20px; width: 200px; } input::-webkit-input-placeholder { font-size: 14px; } .submit-btn { width: 100%; height: 50px; position: fixed; bottom: 0; left: 0; background: white; border: none; font-size: 22px; letter-spacing: 4px; color: #faac08; } </style>