从零开始,搭建一个简单的购物平台(十六)前端商城部分:
https://blog.csdn.net/time_____/article/details/108769229
项目源码(持续更新):https://gitee.com/DieHunter/myCode/tree/master/shopping
上篇文章讲到了商品详情页面实现,最后一个功能是加入购物车,也就是通过列表对比商品是否存在,若存在,则对现有商品数据进行修改,若不存在,则初始化商品,并添加至购物车列表中,这篇文章将介绍对购物车数据进行操作功能
购物车功能包括
修改商品数量 删除单个商品 全选/反选 批量删除
这个页面,将其分解成四个组件,分别是顶部的Title,菜单栏Tabbar,单件商品shopCarItem和下面的批量操作shopCarOrder
修改商品数量在上篇文章中已介绍,通过countShopItem方法进行修改
删除单个商品
delShopItem(_id) { let _shopCar = this.state//获取现有购物车列表 _shopCar.splice(_id, 1)//数组删除第_id项 this.state = _shopCar//刷新购物车列表 this.$events.emitEvent(EventName.CountShop);//刷新界面 }
全选/反选,这里有两个注意的地方,全选/反选的实现有两种状态,一是每个商品单选被全选或反选后全选按钮也会跟随状态,二是全选按钮全选或反选后所有单选按钮也会跟随状态
我们首先在store的action加一个方法,用于总计商品的全选状态,商品总数,及总价格。每当商品被选中,就触发这个方法,刷新数据
filterSelect() {//修改商品全选,单个商品驱动全选按钮,刷新数据 let shopConfig = {//所有商品总计初始值 _count: 1,//是否全选 _selCount: 0,//商品总数 _sum: 0//商品总价 } this.state.forEach(item => { shopConfig._selCount += item.isSelect ? 1 : 0; shopConfig._count *= item.isSelect;//判断是否全选,初始值0,若全为false,相乘等于0,若全为true,相乘为1,即等于1是全选,等于0是未全选 shopConfig._sum += item.isSelect ? item.sum : 0 }); this.$events.emitEvent(EventName.SelectParent, shopConfig); } 此外,我们需要再写个方法,用于全选按钮修改各个商品的选中状态 selAllChild(_sel) {//修改商品全选,全选按钮驱动单个商品,刷新数据 this.state = this.state.map(item => { item.isSelect = _sel;//当全选按钮选中,修改所有商品状态 return item; }); this.$events.emitEvent(EventName.SelectAllChild); } 于是在单件商品shopCarItem组件中,我们进行调用action中的方法,修改全局state值 <template> <div> <ul v-if="shopList.length" class="shopCar"> <li v-for="(item,index) in shopList" :key="index"> <span class="mint-checkbox" @click="selectHandler(index)"> <input class="mint-checkbox-input" type="checkbox" :checked="item.isSelect" /> <span class="mint-checkbox-core"></span> </span> <img :src="imgPath+item.shopPic" alt /> <div class="shopInfo"> <div> <span>{{item.shopName}} {{item.shopScale}}克</span> <span>¥{{item.shopPrice}}</span> </div> <div> <mt-button class="minus" type="default" @click="minusShopHandler(item)">-</mt-button> <span>{{item.shopCount}}</span> <mt-button class="add" type="default" @click="addShopHandler(item)">+</mt-button> <mt-button class="del" type="default" @click="delShopHandler(index)">×</mt-button> </div> </div> </li> </ul> <div v-else class="noShop"> <div class="icon-jiarugouwuche iconfont"></div> <span>购物车为空</span> </div> </div> </template> <script> import Config from "../../config/config"; import { Toast } from "mint-ui"; const { EventName } = Config; export default { name: "shopCarItem", data() { return { shopCar: null,//初始化购物车 shopList: [],//购物车列表state imgPath: Config.RequestPath,//静态文件根目录 selectAll: false,//全选 }; }, created() { this.shopCar = new this.$store.ShopCar(); this.shopList = this.shopCar.state; this.$events.onEvent(EventName.CountShop, this.countHandler);//商品数量监听 this.$events.onEvent(EventName.SelectAllChild, this.selAllHandler);//商品全选监听 }, mounted() { this.shopCar.filterSelect();//初始化全选,商品数量,商品总价 }, destroyed() { this.$events.offEvent(EventName.CountShop, this.countHandler); this.$events.offEvent(EventName.SelectAllChild, this.selAllHandler); }, methods: { countHandler(res) {//修改商品数量,刷新数据 this.shopList = this.shopCar.state; this.shopCar.filterSelect(); }, selectHandler(_id) {//修改商品全选,单个商品驱动全选按钮,刷新数据 this.shopList[_id].isSelect = !this.shopList[_id].isSelect; this.shopCar.state = this.shopList; this.shopCar.filterSelect(); }, selAllHandler() {//修改商品全选,全选按钮驱动单个商品,刷新数据 this.shopList = this.shopCar.state; this.shopCar.filterSelect(); }, addShopHandler(_data) {//添加商品,刷新数据 _data.shopCount = 1; this.shopCar.countShopItem({ ..._data, }); }, minusShopHandler(_data) {//减少商品,刷新数据 _data.shopCount = -1; this.shopCar.countShopItem({ ..._data, }); }, delShopHandler(_id) {//删除单个商品,刷新数据 this.shopCar.delShopItem(_id); }, }, }; </script> <style lang="less" scoped> @import "../../style/init.less"; .noShop { width: 100%; height: 100%; text-align: center; span { .f_s(36); } div { .w(200); .h(200); border-radius: 100%; background: @mainColor; .titleFont(); box-shadow: 5px 5px 8px #777; .l_h(200); text-align: center; margin: 100px auto 20px; .f_s(100); } } .shopCar { .padbottom(130); width: 100%; li { border-bottom: 1px solid #d3d3d3; padding-left: unit(35 / @pxtorem, rem); .h(320); .mint-checkbox { .h(320); .l_h(320); display: inline-block; vertical-align: middle; } .mint-checkbox-input:checked + .mint-checkbox-core { background: #ea3e3c; border-color: #ea3e3c; } img { .h(265); .w(265); margin-left: unit(20 / @pxtorem, rem); display: inline-block; vertical-align: middle; background: #f5f6f5; } .shopInfo { .h(235); width: 50%; .padtop(30); padding-left: unit(10 / @pxtorem, rem); display: inline-block; vertical-align: middle; div:nth-child(1) { overflow: hidden; span { float: left; } span:nth-child(2) { float: right; } } div:nth-child(2) { margin-top: unit(85 / @pxtorem, rem); span { display: inline-block; vertical-align: middle; padding: 0 unit(50 / @pxtorem, rem); } .add, .minus, .del { display: inline-block; vertical-align: middle; background: white; box-shadow: none; .f_s(50); } .del { float: right; } } } } } </style>
在批量操作shopCarOrder组件中同理
<template> <div class="shopOrder"> <span class="mint-checkbox" @click="selectHandler"> <input class="mint-checkbox-input" type="checkbox" :checked="isSelAll" /> <span class="mint-checkbox-core"></span> </span> <span>全选({{selCount}})</span> <span @click="delSelShop">删除({{selCount}})</span> <span> <span>¥{{sum}}</span> <span class="icon-qianjin iconfont" @click="sendOrder"></span> </span> </div> </template> <script> import Config from "../../config/config"; import ShopCarOrderBussiness from "./bussiness"; import { Toast } from "mint-ui"; const { EventName } = Config; export default { name: "shopCarOrder", data() { return { shopCar: null, isSelAll: false,//全选 selCount: 0,//商品数量 sum: 0,//商品总价 orderList: null,//提交订单请求参数 shopCarOrderBussiness: null, }; }, created() { this.shopCar = new this.$store.ShopCar(); this.shopCarOrderBussiness = new ShopCarOrderBussiness(this); this.$events.onEvent(EventName.SelectParent, this.selAllHandler);//全选按钮监听,通过监听所有商品都选中或未全选,修改状态 }, destroyed() { this.$events.offEvent(EventName.SelectParent, this.selAllHandler); }, methods: { selectHandler() {//驱动修改所有商品选中状态 this.isSelAll = !this.isSelAll; this.shopCar.selAllChild(this.isSelAll); }, selAllHandler({ _count, _selCount, _sum }) { this.isSelAll = _count; this.selCount = _selCount; this.sum = _sum; }, delSelShop() {//删除选中商品 this.shopCar.delSelShop(); }, sendOrder() {//提交订单 this.shopCarOrderBussiness.sendOrderList(); }, }, }; </script> <style lang="less" scoped> @import "../../style/init.less"; .shopOrder { .f_s(34); color: #fff; position: fixed; .mcolor(); bottom: unit(130 / @pxtorem, rem); width: 100%; .h(130); .l_h(130); > span:nth-child(1), > span:nth-child(2) { padding-left: unit(35 / @pxtorem, rem); } > span:nth-child(3) { padding-left: unit(200 / @pxtorem, rem); } > span:nth-child(4) { float: right; margin-right: unit(50 / @pxtorem, rem); > span:nth-child(1) { padding-left: unit(20 / @pxtorem, rem); border-left: 1px dashed #fff; } > span:nth-child(2) { padding-left: unit(50 / @pxtorem, rem); } } > span { display: inline-block; } .mint-checkbox-input + .mint-checkbox-core { background: transparent; border-color: #fff; } .mint-checkbox-input:checked + .mint-checkbox-core { .mcolor(); } } </style>
在action中,我们还需要写一个函数,用于删除选中商品
delSelShop() {//直接通过遍历商品选中状态值进行删除,并刷新数据 let _list = [] this.state.map(item => { if (!item.isSelect) { _list.push(item) } }); this.state = _list this.$events.emitEvent(EventName.CountShop); }
最后,在shopCar.vue界面中引入这四个组件,页面实现完成
<template> <div> <Top title="购物车"></Top> <div class="content"> <ShopCarItem></ShopCarItem> <ShopCarOrder></ShopCarOrder> </div> <TabBar></TabBar> </div> </template> <script> import Top from "../../components/top/top"; import ShopCarItem from "../../components/shopCarItem/shopCarItem"; import ShopCarOrder from "../../components/shopCarOrder/shopCarOrder"; import TabBar from "../../components/tabBar/tabBar"; export default { name: "shopCar", data() { return {}; }, components: { Top, ShopCarItem, ShopCarOrder, TabBar }, created() {} }; </script> <style lang="less" scoped> @import "../../style/init.less"; </style>
本篇文章主要对商品购物车操作进行了介绍,其中运用了数据刷新视图的基本操作,将数据,逻辑,视图三者分开,结合vue的数据绑定渲染页面。下篇文章将实现用户的注册,登录功能(简单的用户名密码注册,登录,和邮箱验证模块)