Vue.js 2 项目实战(五):水果购物车

前言

Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它的设计目标是通过采用易于上手的结构和强大的功能,使前端开发变得更加简便和高效。以下是 Vue.js 的一些关键特性和优点:

核心特性

  1. 声明式渲染

    • Vue.js 使用声明式语法来描述用户界面,数据和视图是双向绑定的。当数据变化时,视图会自动更新。
  2. 组件系统

    • Vue.js 提供了一个灵活的组件系统,允许开发者将 UI 分解成可复用的组件,每个组件都有自己的逻辑和样式。
  3. 单文件组件 (SFC)

    • Vue.js 允许开发者将 HTML、CSS 和 JavaScript 放在同一个 .vue 文件中,这样可以更容易地管理组件。
  4. 虚拟 DOM

    • Vue.js 使用虚拟 DOM 来优化更新过程,通过最小化实际 DOM 操作来提高性能。
  5. 反应式数据绑定

    • Vue.js 提供了响应式的数据绑定系统,使得数据与 DOM 之间的同步变得简单和高效。
  6. 指令

    • Vue.js 提供了一组内置指令(如 v-bindv-modelv-for),帮助开发者轻松地操作 DOM。

优点

  1. 易于上手

    • Vue.js 的学习曲线较低,适合新手入门,并且文档详细、社区活跃。
  2. 灵活性

    • Vue.js 可以与现有项目集成,也可以用于构建复杂的单页面应用(SPA)。
  3. 性能高效

    • 得益于虚拟 DOM 和响应式系统,Vue.js 在处理大量数据更新时表现出色。
  4. 生态系统

    • Vue.js 拥有丰富的生态系统,包括 Vue Router、Vuex、Vue CLI 等工具和库,支持开发者在不同场景下使用。
  5. 强大的社区支持

    • Vue.js 有一个全球活跃的社区,提供了大量的插件、教程和支持资源。

知识点

1. v-if v-else 条件渲染,如果没有数据则显示空车

2. v-for 循环遍历渲染数组

3. v-bind 绑定 class 设置条件

4. v-model 绑定属性

5. v-bind 绑定 src

6. 插值语法

7. @click 点击事件实现数量加减

8. filter() 方法更新数组达到删除元素的效果

9. find() 方法通过 id 找到对应的水果

10. :disabled 动态属性绑定限制用户

11. 计算属性完整写法实现全选的两个功能 

12. every() 方法检查每一个元素

13. foreach() 方法设置每一个元素 

14. some() 方法实现如果有任意一个按钮不是 true,则全选,反之取消所有选择

15. reduce() 方法计算总价与数量

16. 判断条件实现没有选中的则不添加

项目效果

初始页面

添加水果

全选按钮

删除水果

本地缓存

源代码

index.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;

inputnumber.css

.my-input-number {position: relative;display: inline-block;width: 140px;line-height: 38px;
}
.my-input-number span {-moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;
}
.my-input-number .my-input {display: block;position: relative;font-size: 14px;width: 100%;
}
.my-input-number .my-input__inner {-webkit-appearance: none;background-color: #fff;background-image: none;border-radius: 4px;border: 1px solid #dcdfe6;box-sizing: border-box;color: #606266;display: inline-block;font-size: inherit;height: 40px;line-height: 40px;outline: none;padding: 0 15px;transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);width: 100%;padding-left: 50px;padding-right: 50px;text-align: center;
}
.my-input-number .my-input-number__decrease,
.my-input-number .my-input-number__increase {position: absolute;z-index: 1;top: 1px;width: 40px;height: auto;text-align: center;background: #f5f7fa;color: #606266;cursor: pointer;font-size: 13px;
}
.my-input-number .my-input-number__decrease {left: 1px;border-radius: 4px 0 0 4px;border-right: 1px solid #dcdfe6;
}
.my-input-number .my-input-number__increase {right: 1px;border-radius: 0 4px 4px 0;border-left: 1px solid #dcdfe6;
}
.my-input-number .my-input-number__decrease.is-disabled,
.my-input-number .my-input-number__increase.is-disabled {color: #c0c4cc;cursor: not-allowed;
}

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="./img/fruit.jpg" alt="Fruit"></div><!-- 面包屑 --><div class="breadcrumb"><span>🏠</span>/<span>购物车</span></div><!-- 购物车主体 --><!-- v-if v-else 条件渲染,如果没有数据则显示空车 --><div v-if="fruitList.length > 0" class="main"><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><!-- 身体 --><!-- v-for 循环遍历渲染数组 --><div v-for="(item, index) in fruitList" :key="item.id" class="tbody"><!-- v-bind 绑定 class 设置条件--><div class="tr" :class="{ active: item.isChecked }"><!-- v-model 绑定属性 --><div class="td"><input type="checkbox" v-model="item.isChecked" /></div><!-- v-bind 绑定 src --><div class="td"><img :src="item.icon" alt="" /></div><div class="td">{{ item.price }}</div><div class="td"><div class="my-input-number"><!-- @click 点击事件实现数量加减 --><!-- :disabled 是一个动态属性绑定,它允许你根据表达式的结果动态地设置 HTML 元素的 disabled 属性 --><button :disabled="item.num <= 1" class="decrease" @click="item.num--"> - </button><span class="my-input__inner">{{ item.num }}</span><button class="increase" @click="item.num++"> + </button></div></div><div class="td">{{ item.price * item.num }}</div><div @click="del(item.id)" class="td"><button>删除</button></div></div></div></div><!-- 底部 --><div class="bottom"><!-- 全选 --><label class="check-all"><!-- v-model 绑定计算属性实现全选功能 --><input type="checkbox" v-model="isAll" @click=""/>全选</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 v-else class="empty">🛒空空如也</div></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>// 初始页面给出默认数组const defultArr = [{id: 1,icon: './img/火龙果.png',isChecked: true,num: 2,price: 6,},{id: 2,icon: './img/荔枝.png',isChecked: false,num: 7,price: 20,},{id: 3,icon: './img/榴莲.png',isChecked: false,num: 3,price: 40,},{id: 4,icon: './img/鸭梨.png',isChecked: true,num: 10,price: 3,},{id: 5,icon: './img/樱桃.png',isChecked: false,num: 20,price: 34,},]const app = new Vue({el: '#app',data: {// localStorage.getItem 是 Web 存储 API 的一部分,用于从本地存储中获取键名为 'list' 的数据项// JSON.parse 函数用于将 JSON 格式的字符串转换为 JavaScript 对象。如果从 localStorage 获取的字符串是有效的 JSON 字符串,它将被转换为对应的 JavaScript 对象// || 是逻辑或运算符。如果 JSON.parse(localStorage.getItem('list')) 的结果为 null 或 undefined(即本地存储中没有 'list' 键或其值为 null),则使用 defaultArr 作为默认值fruitList: JSON.parse(localStorage.getItem('list')) || defultArr ,},computed: {// 默认计算属性只能获取不能设置// 通过 every 检查每个水果的选中状态,如果都选中则全选按钮选中// isAll () {//   return this.fruitList.every(item => item.isChecked === true)// }// 完整写法 get + setisAll: {// get 用于获取get () {return this.fruitList.every(item => item.isChecked === true)},// set 用于设置set (value) {// 点击按钮时先判断// some() 方法实现如果有任意一个按钮不是 true,则全选,反之取消所有选择if (this.fruitList.some(item => item.isChecked !== true)) {this.fruitList.forEach(item => item.isChecked = true);} else {this.fruitList.forEach(item => item.isChecked = false);}}},totalCount () {return this.fruitList.reduce((sum, item) => {// 判断实现选中状态的才添加if (item.isChecked === true) {return sum + item.num} else {// 没选中则不干,返回 sumreturn sum}}, 0)},totalPrice () {return this.fruitList.reduce((sum, item) => {// 判断实现选中状态的才添加if (item.isChecked === true) {return sum + item.price * item.num} else {return sum}}, 0)}},methods: {del (id) {// filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素// 这是一个箭头函数,它接收数组中的每个元素作为参数(在这里是 item)。// item.id !== id:这是一个比较操作,检查 item 的 id 属性是否不等于传递给 filter 方法的 id 参数。如果不等于,返回 true;如果等于,返回 falsethis.fruitList = this.fruitList.filter(item => item.id !== id)},},// 使用 watch 监视数据保存到本地实现持久化// watch 是 Vue 实例的一个选项,用于定义一个或多个观察者,观察者可以观察 Vue 实例的数据变化watch: {fruitList: {deep: true,handler (newValue) {// 使用 $nextTick 确保在 DOM 更新完成后保存数据this.$nextTick(() => {// 需要将变化后的数据(newValue)存储本地(转 JSON)// localStorage.setItem('list', JSON.stringify(newValue)) 将 fruitList 数组的新值转换为 JSON 字符串,并存储到浏览器的本地存储中。// localStorage 是 Web 存储 API 的一部分,允许存储键值对数据,数据在页面会话结束时会被清除// JSON.stringify(newValue) 将 newValue(一个数组)转换为一个 JSON 格式的字符串,以便存储在本地存储中localStorage.setItem('list', JSON.stringify(newValue));});}}}})</script></body>
</html>

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

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

相关文章

OpenAI深夜丢炸弹硬杠谷歌搜索

这几年科技变革太快&#xff0c;AI更是飞速发展&#xff0c;作为一名IT老兵&#xff0c;使用过的搜索引擎也是一换再换。这不&#xff0c;刚消停了一段时间的OpenAI又丢出一个炸弹SearchGPT&#xff0c;直接跟谷歌掀桌子了。 1、谷歌搜索的无奈 早年只能用用百度搜索或者其余…

C++学习:C++是如何运行的

C 是一种强类型的编程语言&#xff0c;支持面向对象、泛型和低级内存操作。它的工作机制包括从编写源代码到生成可执行文件的一系列步骤。C与文件无关&#xff0c;文件只是容纳运行内容的载体&#xff0c;需要对文件以目标系统的规则编译后&#xff0c;才能在目标系统中运行。 …

JAVA SE 类和对象

类和对象 类定义和使用类的定义格式 类的实例化什么是实例化 this 引用this引用的特性 对象的构造及初始化如何初始化对象构造方法概念特性 在这里插入图片描述 **注意**&#xff1a; 封装封装的概念封装扩展之包导入包中的类自定义包包的访问权限控制举例 static成员static修饰…

微信小游戏之 三消(一)

首先设定一下 单个 方块 cell 类&#xff1a; 类定义和属性 init 方法 用于初始化方块&#xff0c;接收游戏实例、数据、宽度、道具类型和位置。 onWarning 方法 设置警告精灵的帧&#xff0c;并播放闪烁动作&#xff0c;用于显示方块的警告状态。 grow 方法 根据传入的方向…

磨煤机加载油站系统比例阀放大器

磨煤机液压系统是火力发电厂中不可或缺的重要组成部分&#xff0c;它主要负责为磨煤机提供并调节必须的碾磨压力。这一系统的核心功能是通过BEUEC比例放大器配套比例溢流阀精确控制&#xff0c;以适应煤炭处理过程中对压力的不同需求&#xff0c;确保煤炭的有效碾磨及火力发电的…

C语言 | Leetcode C语言题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; int hIndex(int* citations, int citationsSize) {int left 0, right citationsSize - 1;while (left < right) {int mid left (right - left) / 2;if (citations[mid] > citationsSize - mid) {right mid - 1;} else {left mi…

Jenkins持续集成软件

1.什么是jenkins? jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;提供一个开放易用的软件平台&#xff0c;时软件项目可以进行持续集成。 通俗来说&#xff1a;Jenkins软件就是自动拉取git远程仓库所…

Java 面试相关问题(下)——JVM相关问题GC相关问题

1. 类加载1.1 类的生命周期说一下&#xff1f;1.2 介绍下生命周期中的加载&#xff1f;1.3 介绍下生命周期中的验证&#xff1f;1.4 介绍下生命周期中的准备&#xff1f;1.5 介绍下生命周期中的解析&#xff1f;1.6 介绍下生命周期中的初始化&#xff1f;1.7 介绍下生命周期中的…

秋叶大神中文版Stable Diffusion下载安装使用教程

Stable Diffusion是什么&#xff1f; Stable Diffusion是一款开源的AI绘画软件&#xff0c;于2022年发布&#xff0c;由CompVis、Stability AI和LAION的研究人员创建。该软件具有出色的图像生成功能&#xff0c;使用户能够从头开始绘制作品&#xff0c;也可以使用现有的图像进…

花几千上万学习Java,真没必要!(三十)

异常&#xff1a; 测试测试代码1&#xff1a; package catchtest.com; public class TryCatchExample { //使用一个或多个 catch 块捕获并处理异常。public static void main(String[] args) { try { // 尝试执行的代码块 int result 10 / 0; // 引发 ArithmeticExceptio…

AI如何助力UI设计师互联网学习?

嘿&#xff0c;咱 UI 设计师想用互联网学习&#xff0c;可真不容易&#xff01;资料筛选难&#xff0c;学习资源杂&#xff0c;真让人头疼。不过还好有 AI 工具能帮忙&#xff0c;提效率&#xff01; 这一年多来&#xff0c;我在 ai123.cn 这个平台上&#xff0c;可算是找到了…

【LeetCode、牛客】链表分割、链表的回文结构、160.相交链表

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构 &#x1f4da;本系列文章为个人学…

Web网页端IM产品RainbowChat-Web的v7.1版已发布

一、关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统&#xff0c;是RainbowChat的姊妹系统&#xff08;RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址) 的产品级移动端IM系统&#xff09;。 ► 详细介绍&#xff1a;http://www.52im.net/thread-2…

WEB前端11-Vue2基础01(项目构建/目录解析/基础案例)

Vue2基础(01) 1.Vue2项目构建 步骤一&#xff1a;安装前端脚手架 npm install -g vue/cli步骤二&#xff1a;创建项目 vue ui步骤三&#xff1a;运行项目 npm run serve步骤四&#xff1a;修改vue相关的属性 DevServer | webpack //修改端口和添加代理 const { defineCo…

AccessLog| 一款开源的日志分析系统

前言 ClkLog作为分析系列产品中的前端数据分析系统&#xff0c;通过采集前端应用数据进行用户行为分析。其社区版从23年9月发布至今已有近一年&#xff0c;商业版也上线快半年&#xff0c;感谢大家一直以来的关注和支持&#xff0c;ClkLog会继续做好产品升级与服务&#xff0c;…

中小企业提升销售效率的10款CRM系统

本文介绍了10款CRM系统&#xff1a;纷享销客、Zoho CRM、Apptivo、简信CRM、浪潮CRM、HubSpot CRM、八百客、简道云、Pipedrive、Insightly。 在选择CRM系统时&#xff0c;中小企业常常面临着预算限制和功能需求之间的矛盾&#xff0c;许多企业希望找到既经济实惠又功能强大的解…

重生之“我打数据结构,真的假的?”--3.栈和队列

1.栈和队列的基本概念 1.1 栈 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则…

深度剖析:品牌推广中的专业外包服务商策略

回顾历史&#xff0c;从农业革命到工业革命&#xff0c;再到如今的信息技术革命&#xff0c;每一次社会生产力的飞跃都伴随着分工的细化和专业化的提升。亚当斯密在《国富论》中提出的“分工论”早已揭示了这一真理&#xff1a;通过分工&#xff0c;每个人专注于自己擅长的领域…

计算机网络(Wrong Question)

一、计算机网络体系结构 1.1 计算机网络概述 D 注&#xff1a;计算机的三大主要功能是数据通信、资源共享、分布式处理。&#xff08;负载均衡、提高可靠性&#xff09; 注&#xff1a;几段链路就是几段流水。 C 注&#xff1a;记住一个基本计算公式&#xff1a;若n个分组&a…