vue实现购物车功能

实现功能

CSS部分

   <style>.tr {display: flex;}.th {margin: 10px;width: 20%;height: 50%;}.td {display: flex;margin: 10px;width: 20%;height: 100px;align-items: center;}.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;}.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;}.empty {text-align: center;font-size: 30px;}/* 选中时颜色是灰色 */.tr.active {background-color: #f5f7fa;}</style>

HTML

<body>
<div class="app-container" id="app"><!-- 顶部banner --><div class="banner-box"><img src="./fruitPot/封面.png" 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 class="tr" :class="{active:item.isChecked}" v-for="(item) in fruitlist" :key="item.id"><div class="td"><input type="checkbox" v-model="item.isChecked"/></div><div class="td pot"><img :src="item.icon" alt=""/></div><div class="td">{{ item.price }}</div><div class="td"><div class="my-input-number"><!--disabled:禁用  --><button :disabled="item.num <=0 " 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.price * item.num}}</div><!-- 删除filter --><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">结算( {{totalNum()}} )</button></div></div></div><!-- 空车 --><div class="empty" v-else>🛒空空如也</div>
</div>

JS

<script><!--    初始化-->// const defaultArr =[ ]const app = new Vue({el: '#app',data: {// // 水果列表从本地读取// // JSON.parse将本地JSON格式转回去// 加||defaultArr是怕用户删除完,下次刷新后只剩下空空如也// fruitlist: JSON.parse(localStorage.getItem('list'))||defaultArr,fruitlist: [{id: 1,icon: './fruitPot/苹果.png',isChecked: true,num: 2,price: 6,},{id: 2,icon: './fruitPot/苹果.png',isChecked: false,num: 7,price: 20,},{id: 3,icon: './fruitPot/鸭梨.png',isChecked: true,num: 2,price: 6,},],},// 计算属性computed: {isAll:{// isAll:  对象// get()   方法get(){// 必须所有的小选框都选中,全选按钮才选中--every// 此时的item与上面的item没关联,只是一个形参return this.fruitlist.every(item => {return  item.isChecked===true})},// value是复选框的布尔值set(value){//console.log(value)  ture/false//基于拿到的布尔值,要让所有的小选框同步状态this.fruitlist.forEach(item =>item.isChecked = value)}}},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) {const fruit = this.fruitlist.find(item => item.id === id)fruit.num--},//     总数量  reducetotalNum(){return this.fruitlist.reduce((sum, item) => {if (item.isChecked) {// 选中 → 需要累加return sum + item.num} else {// 没选中 → 不需要累加return sum}}, 0)},// 总价totalPrice(){return this.fruitlist.reduce((sum, item) => {if (item.isChecked) {return sum + item.num * item.price} else {return sum}}, 0)},},//     监视数据变化watch:{fruitlist:{deep:true,handler(newValue){console.log(newValue)//     需要将变化后的newValue存入本地(转JSON)localStorage.setItem('list',JSON.stringify(newValue))}}}})
</script>

全部代码

<!-- 标签\watch\methods -->
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>水果购物车</title><style>.tr {display: flex;}.th {margin: 10px;width: 20%;height: 50%;}.td {display: flex;margin: 10px;width: 20%;height: 100px;align-items: center;}.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;}.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;}.empty {text-align: center;font-size: 30px;}/* 选中时颜色是灰色 */.tr.active {background-color: #f5f7fa;}</style>
</head>
<body>
<div class="app-container" id="app"><!-- 顶部banner --><div class="banner-box"><img src="./fruitPot/封面.png" 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 class="tr" :class="{active:item.isChecked}" v-for="(item) in fruitlist" :key="item.id"><div class="td"><input type="checkbox" v-model="item.isChecked"/></div><div class="td pot"><img :src="item.icon" alt=""/></div><div class="td">{{ item.price }}</div><div class="td"><div class="my-input-number"><!--disabled:禁用  --><button :disabled="item.num <=0 " 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.price * item.num}}</div><!-- 删除filter --><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">结算( {{totalNum()}} )</button></div></div></div><!-- 空车 --><div class="empty" v-else>🛒空空如也</div>
</div><script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script><script><!--    初始化-->// const defaultArr =[ ]const app = new Vue({el: '#app',data: {// // 水果列表从本地读取// // JSON.parse将本地JSON格式转回去// 加||defaultArr是怕用户删除完,下次刷新后只剩下空空如也// fruitlist: JSON.parse(localStorage.getItem('list'))||defaultArr,fruitlist: [{id: 1,icon: './fruitPot/苹果.png',isChecked: true,num: 2,price: 6,},{id: 2,icon: './fruitPot/苹果.png',isChecked: false,num: 7,price: 20,},{id: 3,icon: './fruitPot/鸭梨.png',isChecked: true,num: 2,price: 6,},],},// 计算属性computed: {isAll:{// isAll:  对象// get()   方法get(){// 必须所有的小选框都选中,全选按钮才选中--every// 此时的item与上面的item没关联,只是一个形参return this.fruitlist.every(item => {return  item.isChecked===true})},// value是复选框的布尔值set(value){//console.log(value)  ture/false//基于拿到的布尔值,要让所有的小选框同步状态this.fruitlist.forEach(item =>item.isChecked = value)}}},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) {const fruit = this.fruitlist.find(item => item.id === id)fruit.num--},//     总数量  reducetotalNum(){return this.fruitlist.reduce((sum, item) => {if (item.isChecked) {// 选中 → 需要累加return sum + item.num} else {// 没选中 → 不需要累加return sum}}, 0)},// 总价totalPrice(){return this.fruitlist.reduce((sum, item) => {if (item.isChecked) {return sum + item.num * item.price} else {return sum}}, 0)},},//     监视数据变化watch:{fruitlist:{deep:true,handler(newValue){console.log(newValue)//     需要将变化后的newValue存入本地(转JSON)localStorage.setItem('list',JSON.stringify(newValue))}}}})
</script>
</body>
</html>

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

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

相关文章

input中文输入法导致的高频事件

这是基本结构 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>中文输入法的高频事件</title&…

以题为例 浅谈前缀和算法

前缀求和算法是什么 前缀和算法就是以空间去换取时间&#xff0c;可用于快速求数组的区间和&#xff0c;它可以用于一维数组和二维数组&#xff0c;但我现在只接触了一维数组并没有接触二维数组&#xff0c;所以在这里先介绍一维数组前缀和相关的知识 前缀和典型代码 for(int…

通信-CAN-01 总线拓扑

本文主要介绍CAN总线拓扑&#xff0c;并结合实际用到CAN设备做些说明。 1 总线拓扑 拓扑结构中分为CPU&#xff0c;CAN 控制器&#xff0c;收发器&#xff0c;双绞线。CAN控制器根据两根线上的电位差来判断总线电平。发送方通过使总线发生变化&#xff0c;将消息发送给接收方…

BPSK调制解调

BPSK数字调制是相移键控PSK的一种&#xff0c;通过数字信号&#xff0c;调制载波的相位&#xff0c;利用载波的相位变化来反映数字信号&#xff0c;载波的振幅和频率均不变化。PSK应用很广泛&#xff0c;抗噪声性能比ASK和FSK要好&#xff0c;频带利用率较高。BPSK中&#xff0…

探讨:C#运行程序文件并获取输出的小问题

尝试了一下用C#运行一个控制台程序&#xff0c;希望获取输出并在适当的时候输入&#xff0c;看起来挺简单&#xff0c;不过实际使用发现只能让程序一次性执行完毕并获取输出&#xff08;并没有仔细尝试各种方式&#xff09;。 代码很简单&#xff1a; private void Test(){Proc…

Java实战:Spring Boot 利用 Redis 解决海量重复提交问题

本文将详细介绍如何在 Spring Boot 应用程序中利用 Redis 解决海量重复提交问题。我们将深入探讨重复提交问题的原因和影响&#xff0c;以及如何使用 Redis 的数据结构和原子操作来控制请求的重复提交。 1. 引言 在现代的互联网应用中&#xff0c;用户可能会频繁地提交相同的…

前端文件流、切片下载和上传

前端文件流、切片下载和上传技术在提升文件传输效率和优化用户体验方面发挥着关键作用。这些技术不仅可以帮助解决大文件传输过程中可能遇到的问题&#xff0c;如网络超时、内存溢出等&#xff0c;还能通过并行传输和断点续传等功能&#xff0c;提高传输速度和稳定性。 一、前端…

C++高级面试提:请解释 C++ 中的指针算术和指针迭代器的区别。

请解释 C 中的指针算术和指针迭代器的区别。 在 C 中&#xff0c;指针算术&#xff08;Pointer Arithmetic&#xff09;和指针迭代器&#xff08;Pointer Iterators&#xff09;是处理指针的两种不同方法。 指针算术&#xff08;Pointer Arithmetic&#xff09;&#xff1a; …

webpack5基础--07_自动清空上次打包资源

自动清空上次打包资源 1. 配置 const path require("path");module.exports {entry: "./src/main.js",output: {path: path.resolve(__dirname, "dist"),filename: "static/js/main.js",clean: true, // 自动将上次打包目录资源清…

每日学习笔记:C++ 11的Tuple

#include <tuple> Tuple介绍(不定数的值组--可理解为pair的升级版) 定义 创建 取值 初始化 获取tuple元素个数、获取tuple某元素类型、将2个tuple类型串接为1个新tuple类型

解决Ubuntu 16.04/18.04 图形化界面异常、鼠标光标消失、鼠标变成叉叉等问题

bug场景&#xff1a; 一切从一次换源说起…叭叭叭 这篇文章解决的问题&#xff1a; 1.换源&#xff0c;默认源太慢&#xff0c;换成可用的阿里云的源 2.apt-get failed to …问题 3.图形化异常问题 4.get unmet dependence 问题 5. 鼠标光标消失和鼠标变成叉叉问题。 解决方…

【Python】time模块

专栏文章索引&#xff1a;Python 目录 一、介绍​编辑 二、常用函数​编辑 一、介绍 Python 的 time 模块提供了处理时间的函数。 二、常用函数 1.time()&#xff1a;返回当前时间的时间戳&#xff08;从1970年1月1日开始计时的秒数&#xff09;。 import timecurrent_ti…

Android Gradle 开发与应用 (五) : 基于Gradle 8.2,创建Gradle插件

1. 前言 本文介绍在Android中&#xff0c;如何基于Gradle 8.2&#xff0c;创建Gradle插件。 1.1 本文环境 Android Studio 版本 : Android Studio Hedgehog | 2023.1.1Gralde版本 : gradle 8.2 使用 Android Gradle 插件升级助理 Android Gradle 插件版本说明 1.2 为什么要写…

蓝桥杯递推与递归法|斐波那契数列|数字三角形|42点问题|数的计算|数的划分(C++)

递归是用来做dfs&#xff0c;是搜索算法的基础 递推是用来做dp部分&#xff0c;及部分其他算法&#xff0c;复杂度较低&#xff0c;不会出现爆栈问题递推法&#xff1a; 递推法是一种在数学和其他领域广泛应用的重要方法&#xff0c;它在计算机科学中被用作一种关键的数值求解…

无源元器件-电阻电容磁珠电感选型参数总

🏡《总目录》 目录 1,概述2,电阻选型参数2,电容选型参数3,磁珠选型参数4,电感选型参数1,概述 无源器件(电阻、电容、电感)的选型时,需要考虑的参数多种多样,这些参数的选择会直接影响到电路的性能、稳定性、成本等多个方面。本文对电阻电容磁珠电感的参数进行详细介…

LLM 推理优化探微 (3) :如何有效控制 KV 缓存的内存占用,优化推理速度?

编者按&#xff1a; 随着 LLM 赋能越来越多需要实时决策和响应的应用场景&#xff0c;以及用户体验不佳、成本过高、资源受限等问题的出现&#xff0c;大模型高效推理已成为一个重要的研究课题。为此&#xff0c;Baihai IDP 推出 Pierre Lienhart 的系列文章&#xff0c;从多个…

C/C++指针详解

接下来我们来介绍一下什么是指针&#xff1f; 指针其实就是元素存放地址&#xff0c;更加形象的比喻&#xff1a;在酒店中如果你想要去注必须去付费不然不能住&#xff0c;在计算机也同样如此&#xff08;但是不需要付费哦&#xff09;每当我们使用一个变量或其他需要申请空间…

Linux centos6安装rz、sz命令

centos6传文件提示command not found # yum install lrzsz 提示错误 wget http://www.ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz 下载离线包 https://www.ohse.de/uwe/software/lrzsz.html 下载最新版本 [rootnode1 ~]# tar -zxvf lrzsz-0.12.20.tar.gz …

理论学习 消融实验

消融实验的目的在于移除系统中的特定的部分&#xff0c;来控制变量式的研究这个部分对于系统整体的影响。如果去除这一部分后系统的性能没有太大损失&#xff0c;那么说明这一部分对于整个系统而言并不具有太大的重要性&#xff1b;如果去除之后系统性能明显的下降&#xff0c;…

天啊,腾讯云轻量服务器流量用完了怎么办?

腾讯云轻量服务器流量用完了怎么办&#xff1f;超额部分的流量另外支付流量费&#xff0c;流量价格为0.8元/GB&#xff0c;会自动扣你的腾讯云余额&#xff0c;如果你的腾讯云账号余额不足&#xff0c;那么你的轻量应用服务器会面临停机&#xff0c;停机后外网无法访问&#xf…