08.智慧商城——购物车布局、全选反选、功能实现
01. 购物车 - 静态布局

- 基本结构
<template><div class="cart"><van-nav-bar title="购物车" fixed /><!-- 购物车开头 --><div class="cart-title"><span class="all">共<i>4</i>件商品</span><span class="edit"><van-icon name="edit" />编辑</span></div><!-- 购物车列表 --><div class="cart-list"><div class="cart-item" v-for="item in 10" :key="item"><van-checkbox></van-checkbox><div class="show"><img src="http://cba.itlike.com/public/uploads/10001/20230321/a072ef0eef1648a5c4eae81fad1b7583.jpg" alt=""></div><div class="info"><span class="tit text-ellipsis-2">新Pad 14英寸 12+128 远峰蓝 M6平板电脑 智能安卓娱乐十核游戏学习二合一 低蓝光护眼超清4K全面三星屏5GWIFI全网通 蓝魔快本平板</span><span class="bottom"><div class="price">¥ <span>1247.04</span></div><div class="count-box"><button class="minus">-</button><input class="inp" :value="4" type="text" readonly><button class="add">+</button></div></span></div></div></div><div class="footer-fixed"><div class="all-check"><van-checkbox icon-size="18"></van-checkbox>全选</div><div class="all-total"><div class="price"><span>合计:</span><span>¥ <i class="totalPrice">99.99</i></span></div><div v-if="true" class="goPay">结算(5)</div><div v-else class="delete">删除</div></div></div></div>
</template><script>
export default {name: 'CartPage'
}
</script><style lang="less" scoped>
// 主题 padding
.cart {padding-top: 46px;padding-bottom: 100px;background-color: #f5f5f5;min-height: 100vh;.cart-title {height: 40px;display: flex;justify-content: space-between;align-items: center;padding: 0 10px;font-size: 14px;.all {i {font-style: normal;margin: 0 2px;color: #fa2209;font-size: 16px;}}.edit {.van-icon {font-size: 18px;}}}.cart-item {margin: 0 10px 10px 10px;padding: 10px;display: flex;justify-content: space-between;background-color: #ffffff;border-radius: 5px;.show img {width: 100px;height: 100px;}.info {width: 210px;padding: 10px 5px;font-size: 14px;display: flex;flex-direction: column;justify-content: space-between;.bottom {display: flex;justify-content: space-between;.price {display: flex;align-items: flex-end;color: #fa2209;font-size: 12px;span {font-size: 16px;}}.count-box {display: flex;width: 110px;.add,.minus {width: 30px;height: 30px;outline: none;border: none;}.inp {width: 40px;height: 30px;outline: none;border: none;background-color: #efefef;text-align: center;margin: 0 5px;}}}}}
}.footer-fixed {position: fixed;left: 0;bottom: 50px;height: 50px;width: 100%;border-bottom: 1px solid #ccc;background-color: #fff;display: flex;justify-content: space-between;align-items: center;padding: 0 10px;.all-check {display: flex;align-items: center;.van-checkbox {margin-right: 5px;}}.all-total {display: flex;line-height: 36px;.price {font-size: 14px;margin-right: 10px;.totalPrice {color: #fa2209;font-size: 18px;font-style: normal;}}.goPay, .delete {min-width: 100px;height: 36px;line-height: 36px;text-align: center;background-color: #fa2f21;color: #fff;border-radius: 18px;&.disabled {background-color: #ff9779;}}}}
</style>
- 按需导入组件
import { Checkbox } from 'vant'
Vue.use(Checkbox)
02. 购物车 - 构建 vuex 模块 - 获取数据存储
- 新建
modules/cart.js模块
export default {namespaced: true,state () {return {cartList: []}},mutations: {},actions: {},getters: {}
}
- 挂载到 store 上面
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import cart from './modules/cart'Vue.use(Vuex)export default new Vuex.Store({getters: {token: state => state.user.userInfo.token},modules: {user,cart}
})
- 封装 API 接口
api/cart.js
// 获取购物车列表数据
export const getCartList = () => {return request.get('/cart/list')
}
- 封装 action 和 mutation
mutations: {setCartList (state, newList) {state.cartList = newList},
},
actions: {async getCartAction (context) {const { data } = await getCartList()data.list.forEach(item => {item.isChecked = true})context.commit('setCartList', data.list)}
},
- 页面中 dispatch 调用
computed: {isLogin () {return this.$store.getters.token}
},
created () {if (this.isLogin) {this.$store.dispatch('cart/getCartAction')}
},
03. 购物车 - mapState - 渲染购物车列表
- 将数据映射到页面
import { mapState } from 'vuex'computed: {...mapState('cart', ['cartList'])
}
- 动态渲染
<!-- 购物车列表 -->
<div class="cart-list"><div class="cart-item" v-for="item in cartList" :key="item.goods_id"><van-checkbox icon-size="18" :value="item.isChecked"></van-checkbox><div class="show" @click="$router.push(`/prodetail/${item.goods_id}`)"><img :src="item.goods.goods_image" alt=""></div><div class="info"><span class="tit text-ellipsis-2">{{ item.goods.goods_name }}</span><span class="bottom"><div class="price">¥ <span>{{ item.goods.goods_price_min }}</span></div><CountBox :value="item.goods_num"></CountBox></span></div></div>
</div>
04. 购物车 - 封装 getters - 动态计算展示
- 封装 getters:商品总数 / 选中的商品列表 / 选中的商品总数 / 选中的商品总价
getters: {cartTotal (state) {return state.cartList.reduce((sum, item, index) => sum + item.goods_num, 0)},selCartList (state) {return state.cartList.filter(item => item.isChecked)},selCount (state, getters) {return getters.selCartList.reduce((sum, item, index) => sum + item.goods_num, 0)},selPrice (state, getters) {return getters.selCartList.reduce((sum, item, index) => {return sum + item.goods_num * item.goods.goods_price_min}, 0).toFixed(2)}
}
- 页面中 mapGetters 映射使用
computed: {...mapGetters('cart', ['cartTotal', 'selCount', 'selPrice']),
},<!-- 购物车开头 -->
<div class="cart-title"><span class="all">共<i>{{ cartTotal || 0 }}</i>件商品</span><span class="edit"><van-icon name="edit" />编辑</span>
</div><div class="footer-fixed"><div class="all-check"><van-checkbox icon-size="18"></van-checkbox>全选</div><div class="all-total"><div class="price"><span>合计:</span><span>¥ <i class="totalPrice">{{ selPrice }}</i></span></div><div v-if="true" :class="{ disabled: selCount === 0 }" class="goPay">结算({{ selCount }})</div><div v-else :class="{ disabled: selCount === 0 }" class="delete">删除({{ selCount }})</div></div>
</div>
05. 购物车 - 全选反选功能
- 全选 getters
getters: {isAllChecked (state) {return state.cartList.every(item => item.isChecked)}
}...mapGetters('cart', ['isAllChecked']),<div class="all-check"><van-checkbox :value="isAllChecked" icon-size="18"></van-checkbox>全选
</div>
- 点击小选,修改状态
<van-checkbox @click="toggleCheck(item.goods_id)" ...></van-checkbox>toggleCheck (goodsId) {this.$store.commit('cart/toggleCheck', goodsId)
},mutations: {toggleCheck (state, goodsId) {const goods = state.cartList.find(item => item.goods_id === goodsId)goods.isChecked = !goods.isChecked},
}
- 点击全选,重置状态
<div @click="toggleAllCheck" class="all-check"><van-checkbox :value="isAllChecked" icon-size="18"></van-checkbox>全选
</div>toggleAllCheck () {this.$store.commit('cart/toggleAllCheck', !this.isAllChecked)
},mutations: {toggleAllCheck (state, flag) {state.cartList.forEach(item => {item.isChecked = flag})},
}
06. 购物车 - 数字框修改数量
- 封装 api 接口
// 更新购物车商品数量
export const changeCount = (goodsId, goodsNum, goodsSkuId) => {return request.post('/cart/update', {goodsId,goodsNum,goodsSkuId})
}
- 页面中注册点击事件,传递数据
<CountBox :value="item.goods_num" @input="value => changeCount(value, item.goods_id, item.goods_sku_id)"></CountBox>changeCount (value, goodsId, skuId) {this.$store.dispatch('cart/changeCountAction', {value,goodsId,skuId})
},
- 提供 action 发送请求, commit mutation
mutations: {changeCount (state, { goodsId, value }) {const obj = state.cartList.find(item => item.goods_id === goodsId)obj.goods_num = value}
},
actions: {async changeCountAction (context, obj) {const { goodsId, value, skuId } = objcontext.commit('changeCount', {goodsId,value})await changeCount(goodsId, value, skuId)},
}
07. 购物车 - 编辑切换状态
- data 提供数据, 定义是否在编辑删除的状态
data () {return {isEdit: false}
},
- 注册点击事件,修改状态
<span class="edit" @click="isEdit = !isEdit"><van-icon name="edit" />编辑
</span>
- 底下按钮根据状态变化
<div v-if="!isEdit" :class="{ disabled: selCount === 0 }" class="goPay">去结算({{ selCount }})
</div>
<div v-else :class="{ disabled: selCount === 0 }" class="delete">删除</div>
- 监视编辑状态,动态控制复选框状态
watch: {isEdit (value) {if (value) {this.$store.commit('cart/toggleAllCheck', false)} else {this.$store.commit('cart/toggleAllCheck', true)}}
}
08. 购物车 - 删除功能完成
- 查看接口,封装 API ( 注意:此处 id 为获取回来的购物车数据的 id )
// 删除购物车
export const delSelect = (cartIds) => {return request.post('/cart/clear', {cartIds})
}
- 注册删除点击事件
<div v-else :class="{ disabled: selCount === 0 }" @click="handleDel" class="delete">删除({{ selCount }})
</div>async handleDel () {if (this.selCount === 0) returnawait this.$store.dispatch('cart/delSelect')this.isEdit = false
},
- 提供 actions
actions: {// 删除购物车数据async delSelect (context) {const selCartList = context.getters.selCartListconst cartIds = selCartList.map(item => item.id)await delSelect(cartIds)Toast('删除成功')// 重新拉取最新的购物车数据 (重新渲染)context.dispatch('getCartAction')}
},
09. 购物车 - 空购物车处理
- 外面包个大盒子,添加 v-if 判断
<div class="cart-box" v-if="isLogin && cartList.length > 0"><!-- 购物车开头 --><div class="cart-title">...</div><!-- 购物车列表 --><div class="cart-list">...</div><div class="footer-fixed">...</div>
</div><div class="empty-cart" v-else><img src="@/assets/empty.png" alt=""><div class="tips">您的购物车是空的, 快去逛逛吧</div><div class="btn" @click="$router.push('/')">去逛逛</div>
</div>
- 相关样式
.empty-cart {padding: 80px 30px;img {width: 140px;height: 92px;display: block;margin: 0 auto;}.tips {text-align: center;color: #666;margin: 30px;}.btn {width: 110px;height: 32px;line-height: 32px;text-align: center;background-color: #fa2c20;border-radius: 16px;color: #fff;display: block;margin: 0 auto;}
}
相关文章:
08.智慧商城——购物车布局、全选反选、功能实现
01. 购物车 - 静态布局 基本结构 <template><div class"cart"><van-nav-bar title"购物车" fixed /><!-- 购物车开头 --><div class"cart-title"><span class"all">共<i>4</i>件商品…...
金属压块液压打包机比例阀放大器
液压打包机是机电一体化产品,主要由机械系统、液压控制系统、上料系统与动力系统等组成。整个打包过程由压包、回程、提箱、转箱、出包上行、出包下行、接包等辅助时间组成。市场上液压打包机主要分为卧式与立式两种,立式废纸打包机的体积比较小…...
python 自动化福音,30行代码手撸ddt模块
用 python 做过自动化的小伙伴,大多数都应该使用过 ddt 这个模块,不可否认 ddt 这个模块确实挺好用,可以自动根据用例数据,来生成测试用例,能够很方便的将测试数据和测试用例执行的逻辑进行分离。 接下来就带大家一起…...
基于GATK流程化进行SNP calling
在进行变异检测时,以群体基因组重测序数据为例,涉及到的个体基本都是上百个,而其中大多数流程均是重复的步骤。 本文将基于GATK进行SNP calling的流程写入循环,便于批量分析。 1 涉及变量 1.工作目录work_dir/ 2.参考基因组ref…...
【Java SE】如何解读Java的继承和多态的特性?
前言 什么是继承和多态,为什么被称为Java三大特性,这两大特性为我们程序员带来了什么影响呢?是让复杂的代码简化了,还是为程序员写代码提供了多样性呢?那让我们一起来揭开这层神秘的面纱吧! 1.继承 1.1为…...
uniapp 手动调用form表单submit事件
背景: UI把提交的按钮弄成了图片,之前的button不能用了。 <button form-type"submit">搜索</button> 实现: html: 通过 this.$refs.fd 获取到form的vue对象。手动调用里面的_onSubmit()方法。 methods:…...
11月20日星期一今日早报简报微语报早读
11月20日星期一,农历十月初八,早报微语早读。 1、T1以3-0横扫WBG,拿下S13冠军!Faker豪取第4冠; 2、天舟七号货运飞船已运抵文昌发射场,将于明年初发射; 3、“中韩之战”球票已经售罄…...
Unity中 Start和Awake的区别
Awake和Start在Unity中都是MonoBehaviour脚本中的生命周期函数 Awake函数在游戏对象首次被加载时调用,在游戏对象初始化之前调用。 start函数在游戏对象初始化完成后调用,在update第一次执行前调用。 这两个函数在其生命周期内都只会调用一次…...
进度条、git常见指令以及gdb的常用指令
进度条 进度条是笔者所接触的第一个更加贴近于系统的小玩意,主要是要理解回车、换行、换行回车和缓冲区的概念。 回车是回到当前行的第一个光标位置,换行是换到下一行但是光标还在原来的位置,换行回车就是键盘上面的回车键是回到下一行的第…...
ubuntu20编译安装pkg-config
从下载到安装的步骤如下: wget https://pkg-config.freedesktop.org/releases/pkg-config-0.29.tar.gztar -zxvf pkg-config-0.29.tar.gzcd pkg-config-0.29/./configure --with-internal-glibsudo makesudo make checksudo make install make过程中可能会遇到的问题&#x…...
奇富科技发布鸿蒙元服务1.0版本,打造鸿蒙生态金融科技全新体验
近日,奇富科技率先发布鸿蒙元服务1.0版本,成为首家融入鸿蒙生态的金融科技公司,为用户带来前所未有的数字生活体验。此次与华为终端云的全面合作,是两大行业领军者的深度融合,不仅实现技术的交融,更彰显两大…...
【Git学习一】初始化仓库git init的使用和提交git add与git commit的使用
😁 作者简介:一名大四的学生,致力学习前端开发技术 ⭐️个人主页:夜宵饽饽的主页 ❔ 系列专栏:Git等软件工具技术的使用 👐学习格言:成功不是终点,失败也并非末日,最重要…...
Redux-状态管理组件
一、简介 react中的状态只属于某个组件。而Redux是一个全局管理js状态的架构,让组件通信更加容易。 之前是状态在所有组件间传递,而redux通过store来实现这个功能。 Redux特性: 1.Single source Of truth,通过store唯一维护状态…...
【bigo前端】egret中的对象池浅谈
本文首发于:https://github.com/bigo-frontend/blog/ 欢迎关注、转载。 egret是一款小游戏开发引擎,支持跨平台开发,之前使用这款引擎开发了一款捕鱼游戏,在这里简单聊下再egret中关于对象池的使用,虽然该引擎已经停止…...
用公式告诉你 现货黄金投资者要不要换策略?
看过笔者相关文章的朋友都知道,其实笔者是相当不鼓励投资者更改策略的。但这并不意味着,策略不能改或者换。之所以反对更改策略,是因为很多人对自己的策略还没上手,没了解清楚就急着换策略,这是没必要的。通过下面这个…...
系列六、多线程集合不安全
一、多线程List集合不安全 1.1、List集合不安全案例代码 /*** Author : 一叶浮萍归大海* Date: 2023/11/20 12:38* Description: 多线层环境下List集合不安全案例代码*/ public class NotSafeListMainApp {public static void main(String[] args) {List<String> list …...
MidJourney笔记(1)-入门
注册 MidJourney注册和使用方式,有点特别。在介绍注册之前,需要给大家先介绍Discord。 Discord是一家游戏聊天应用与社区,在国内用的人相对比较少,在国外用得比较多。 那MidJourney和Discord有什么关系呢? MidJourney是搭建在Discord上的一个人工智能程序,通过在Discord添…...
CRM系统定制开发价格
我们都知道,CRM系统对企业有着很大的帮助。但是市面上大多数CRM系统都是标准化的,无法满足那些产品线复杂,或者有着特殊需求的企业。这个时候,就需要对CRM系统进行二次开发。那么,CRM系统二次开发的价格是多少…...
Kubernetes实战(五)-pod之间网络请求实战
1 同namespace内pod网络请求 1.1 创建namespace ygq $ kubectl create namespace ygq namespace/ygq created 1.2 创建svc和deployment 在naemspace ygq下创建两个应用:nginx和nginx-test。 1.2.1 部署应用nginx $ cat nginx-svc.yaml apiVersion: v1 kind: …...
7年经验之谈 —— 如何高效的开展app的性能测试?
APP性能测试是什么 从网上查了一下,貌似也没什么特别的定义,我这边根据自己的经验给出一个自己的定义,如有巧合纯属雷同。 客户端性能测试就是,从业务和用户的角度出发,设计合理且有效的性能测试场景,制定…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
