一、功能需求
- 1、购物车固定显示在点餐页面底部
- 2、实时统计购物车总数量和总金额
- 3、已选菜品展示在购物车
- 4、添加菜品到购物车(菜品列表增加和购物车内增加同步)
- 5、减少菜品到购物车(菜品列表减少和购物车内减少同步)
- 6、购物车蒙层的显示和隐藏
- 7、购物车列表加载缓存菜品信息、已点菜品总数量、总金额
- 8、清空购物车
二、代码实现
1、food.wxml
1 <!-- 搜索 --> 2 <view class="searchRoot"> 3 <input type="text" value="{{searchKey}}" class="searchInput" placeholder="搜索菜品" bindinput="getSearchContent" confirm-type="search" bindconfirm="searchFood"></input> 4 <image src="/images/search.png" class="searchIcon" bindtap="searchFood"></image> 5 </view> 6 7 <!-- 菜品列表 --> 8 <view class="hotFoodRoot"> 9 <view class="hotFoodItem" wx:for="{{foodList}}"> 10 <image src="{{item.icon}}"></image> 11 <view class="hotFoodText"> 12 <view class="itemName">{{item.name}}</view> 13 <view class="itemSell">销量:{{item.sell}}</view> 14 <view class="addAndMinusRoot"> 15 <view class="itemPrice">{{item.price}}</view> 16 <!-- 菜品数量的加减 --> 17 <view class="addAndMinus"> 18 <image class="img" src="/images/minus.png" bindtap="minus" data-id="{{item._id}}"></image> 19 <text class="number">{{item.number}}</text> 20 <image class="img" src="/images/add.png" bindtap="add" data-id="{{item._id}}"></image> 21 </view> 22 </view> 23 </view> 24 </view> 25 </view> 26 <!-- 底部区域 --> 27 <view class="cartRoot"> 28 <view class="cartBackground"> 29 <image class="cartPackage" src="/images/package.png" bindtap="showCart"> 30 <view class="cartNumber"> 31 <text class="totalNumber">{{totalNumber}}</text> 32 </view> 33 </image> 34 <text class="totalMoney">{{totalMoney}}</text> 35 </view> 36 <view class="payMoney">选好了</view> 37 </view> 38 <!-- 购物车蒙层 --> 39 <view class="maskBackground" hidden="{{isHideMask}}"> 40 </view> 41 <!-- 购物车列表 --> 42 <view class="cartDetail" hidden="{{isHideMask}}"> 43 <!-- 标题 --> 44 <view class="cartTitle"> 45 <text class="foodTitle" bindtap="hideCart">返回</text> 46 <view class="delete" bindtap="clearCart"> 47 <image src="/images/delete.png"></image> 48 <text>清空</text> 49 </view> 50 </view> 51 <!-- 数据 --> 52 <scroll-view class="cartData"> 53 <view wx:for="{{cartList}}" class="cartItem"> 54 <image src="{{item.icon}}" class="cartImg"></image> 55 <view class="cartText"> 56 <view class="cartName">{{item.name}}</view> 57 <view class="cartMsg"> 58 <view class="cartPrice">{{item.price}}</view> 59 <!-- 菜品数量的加减 --> 60 <view class="addMinus"> 61 <image class="img" src="/images/minus.png" bindtap="minus" data-id="{{item._id}}"></image> 62 <text class="number">{{item.number}}</text> 63 <image class="img" src="/images/add.png" bindtap="add" data-id="{{item._id}}"></image> 64 </view> 65 </view> 66 </view> 67 </view> 68 </scroll-view> 69 </view>
2、food.wxss
1 /*搜索*/ 2 .searchRoot{ 3 display: flex; 4 flex-direction: row; 5 /*弹性盒内各项元素沿着主轴居中显示*/ 6 align-items: center; 7 padding: 20rpx; 8 } 9 .searchInput{ 10 border: 1rpx solid #FF9966; 11 border-radius: 20rpx; 12 padding: 0 30rpx; 13 flex: 1; 14 height: 76rpx; 15 } 16 .searchIcon{ 17 width: 60rpx; 18 height: 60rpx; 19 margin-left: 20rpx; 20 } 21 /*菜品数据*/ 22 .hotFoodRoot{ 23 /*设置下内边距,防止固定的购物车挡住最后一个菜品*/ 24 padding-bottom: 140rpx; 25 } 26 .hotFoodItem{ 27 display: flex; 28 margin: 20rpx 20rpx 0 20rpx; 29 border-bottom: 1rpx solid rgb(245, 245, 245); 30 } 31 .hotFoodItem image{ 32 width: 120rpx; 33 height: 120rpx; 34 margin-right: 20rpx; 35 border-radius: 10rpx; 36 /*防止标题过长把图片挤走*/ 37 min-width: 120rpx; 38 } 39 40 .hotFoodItem .itemName{ 41 font-size: 32rpx; 42 /*设置菜品名称超过一行时显示省略号*/ 43 width: 500rpx; 44 white-space: nowrap; 45 text-overflow: ellipsis; 46 overflow: hidden; 47 } 48 .hotFoodItem .itemSell{ 49 font-size: 28rpx; 50 color: gray; 51 } 52 53 /*数量加减*/ 54 .addAndMinusRoot{ 55 display: flex; 56 justify-content: space-between; 57 align-items: center; 58 } 59 .addAndMinusRoot .itemPrice{ 60 font-size: 30rpx; 61 color: #FF9966; 62 } 63 .addAndMinusRoot .itemPrice::before{ 64 /*人民币符号*/ 65 content: "¥"; 66 color:#FF9966; 67 } 68 .addAndMinusRoot .addAndMinus{ 69 display: flex; 70 justify-content: flex-end; 71 align-items: center; 72 } 73 .addAndMinus .img{ 74 margin: 0; 75 width: 50rpx; 76 /*必须加上min-width*/ 77 min-width: 50rpx; 78 height: 50rpx; 79 } 80 .addAndMinus .number{ 81 margin: 0 20rpx; 82 } 83 /*底部区域*/ 84 .cartRoot{ 85 width: 100%; 86 display: flex; 87 justify-content: center; 88 /*固定在底部*/ 89 position: fixed; 90 bottom: 20rpx; 91 z-index: 201; 92 } 93 .cartBackground{ 94 width: 450rpx; 95 height: 100rpx; 96 background-color:#fff; 97 border-top-left-radius: 50rpx; 98 border-bottom-left-radius: 50rpx; 99 box-shadow: 0 0 5px gainsboro; 100 display:flex; 101 justify-content: flex-start; 102 align-items: center; 103 } 104 .cartPackage{ 105 width: 80rpx; 106 height: 80rpx; 107 margin: 0 30rpx; 108 position: relative; 109 } 110 .cartNumber{ 111 width: 40rpx; 112 height: 40rpx; 113 border-radius: 50%; 114 background-color:red; 115 position: absolute; 116 top: 0; 117 right: 0; 118 display: flex; 119 align-items: center; 120 justify-content: center; 121 } 122 .totalNumber{ 123 font-size: 24rpx; 124 color: #fff; 125 line-height: 30rpx; 126 } 127 .totalMoney{ 128 font-size: 30rpx; 129 color: #ff9966; 130 } 131 .totalMoney::before{ 132 content: '¥'; 133 font-size: 20rpx; 134 color: #ff9966; 135 } 136 /*去结算*/ 137 .payMoney{ 138 width: 200rpx; 139 height: 100rpx; 140 background-color:#FF9966; 141 border-top-right-radius: 50rpx; 142 border-bottom-right-radius: 50rpx; 143 box-shadow: 0 0 5px gainsboro; 144 text-align: center; 145 line-height: 100rpx; 146 color: #fff; 147 } 148 /*购物车蒙层*/ 149 .maskBackground{ 150 position: fixed; 151 top: 0; 152 right: 0; 153 bottom: 0; 154 left: 0; 155 background-color: gray; 156 /*设置背景颜色透明度*/ 157 opacity: .4; 158 /*设置层级*/ 159 z-index: 100; 160 } 161 162 /*购物车详情*/ 163 .cartDetail{ 164 position: fixed; 165 bottom: 0; 166 left: 0; 167 right: 0; 168 height: 600rpx; 169 background-color: #fff; 170 border-top-left-radius: 20rpx; 171 border-top-right-radius: 20rpx; 172 z-index: 200; 173 /*解决滑动冲突的问题*/ 174 overflow: auto; 175 /*底部内边距,为购物车预留空间*/ 176 padding-bottom: 140rpx; 177 } 178 /*购物车标题*/ 179 .cartTitle{ 180 width: 100%; 181 display: flex; 182 justify-content: space-between; 183 align-items: center; 184 border-bottom: 1rpx solid #f2f2f2; 185 border-top-left-radius: 20rpx; 186 border-top-right-radius: 20rpx; 187 background-color: #fff; 188 height: 80rpx; 189 z-index: 201; 190 /*固定购物车标题*/ 191 position: fixed; 192 left: 0; 193 right: 0; 194 } 195 .cartTitle .foodTitle{ 196 font-size: 28rpx; 197 margin-left: 20rpx; 198 color: #FF9966; 199 } 200 .cartTitle .delete{ 201 display: flex; 202 align-items: center; 203 margin: 20rpx; 204 } 205 .delete image{ 206 width: 40rpx; 207 height: 40rpx; 208 margin-right: 5rpx; 209 } 210 .delete text{ 211 font-size: 28rpx; 212 color: #c3c3c3; 213 } 214 /*购物车数据*/ 215 .cartData{ 216 margin-top: 80rpx; 217 } 218 .cartItem{ 219 display: flex; 220 margin: 20rpx 20rpx 0 20rpx; 221 border-bottom: 1rpx solid rgb(245, 245, 245); 222 } 223 .cartItem .cartImg{ 224 width: 100rpx; 225 height: 100rpx; 226 border-radius: 10rpx; 227 margin-right: 20rpx; 228 /*防止标题过长把图片挤走*/ 229 min-width: 100rpx; 230 } 231 .cartText{ 232 display: flex; 233 flex-direction: column; 234 justify-content:space-around; 235 } 236 .cartItem .cartName{ 237 font-size: 32rpx; 238 /*设置菜品名称超过一行时显示省略号*/ 239 width: 500rpx; 240 white-space: nowrap; 241 text-overflow: ellipsis; 242 overflow: hidden; 243 } 244 245 /*数量加减*/ 246 .cartMsg{ 247 display: flex; 248 justify-content: space-between; 249 align-items: center; 250 } 251 .cartPrice{ 252 font-size: 30rpx; 253 color: #FF9966; 254 } 255 .cartPrice::before{ 256 /*人民币符号*/ 257 content: "¥"; 258 color:#FF9966; 259 } 260 .cartMsg .addMinus{ 261 display: flex; 262 justify-content: flex-end; 263 align-items: center; 264 } 265 .addMinus .img{ 266 margin: 0; 267 width: 50rpx; 268 /*必须加上min-width*/ 269 min-width: 50rpx; 270 height: 50rpx; 271 } 272 .addMinus .number{ 273 margin: 0 20rpx; 274 }
3、food.js
1 //定义db 2 const db = wx.cloud.database() 3 //搜索的菜品信息 4 let foodList = '' 5 //首页传递过来的用户输入的搜索关键词 6 let searchKey = '' 7 8 Page({ 9 //页面的初始数据 10 data: { 11 //搜索内容 12 searchKey:'', 13 //搜索到的菜品数据 14 foodList:[], 15 //购物车的总数量、总金额、菜品信息 16 totalNumber:0, 17 totalMoney:0, 18 cartList:[], 19 //购物车蒙版是否隐藏 20 isHideMask:true 21 }, 22 23 //生命周期函数--监听页面加载 24 onLoad: function (options) { 25 //从首页携带搜索词 26 console.log("从首页携带过来的搜索内容",options.searchKey); 27 searchKey = options.searchKey 28 //如果用户输入关键词搜索 29 if(searchKey&&searchKey.length>0){ 30 this.setData({ 31 searchKey:searchKey 32 }) 33 }else{ //如果用户不输入关键词搜索,则搜索所有菜品 34 searchKey = '' 35 } 36 //获取购物车缓存数据(如果有缓存,则取缓存数据;如果无缓存,则为空数组) 37 let cart = wx.getStorageSync('cart') || [] 38 //将购物车缓存信息渲染到页面上 39 this.setData({ 40 cartList:cart 41 }) 42 //调用自定义方法,执行搜索功能 43 this.searchFood(); 44 }, 45 46 //获取用户输入的搜索内容 47 getSearchContent(e){ 48 console.log("用户输入的搜索内容",e.detail.value); 49 searchKey = e.detail.value 50 }, 51 52 //点击搜索按钮实现功能 53 searchFood(){ 54 console.log("用户点击了搜索按钮,输入的关键词为",searchKey); 55 //购物车菜品信息 56 let cartList = this.data.cartList 57 //使用正则查询 58 db.collection("food").where({ 59 name:db.RegExp({ 60 regexp:searchKey, //搜索池 61 options:'i' //不区分大小写 62 }) 63 }).get() 64 .then(res=>{ 65 console.log("搜索成功",res); 66 foodList = res.data 67 if(foodList&&foodList.length>0){ 68 foodList.forEach(item=>{ 69 //遍历数组foodList,为数组添加新字段number,赋值为0 70 item.number = 0 71 if(cartList&&cartList.length>0){ 72 //检查当前购物车里是否存在当前所选的菜品 73 var res = cartList.find(cart=>{ 74 return cart._id == item._id 75 }) 76 if(res){ 77 item.number = res.number 78 }else{ 79 item.number = 0 80 } 81 } 82 }) 83 this.setData({ 84 foodList:foodList, 85 }) 86 //调用自定义方法,计算购物车总数量和总价格 87 this.getTotal() 88 } 89 }).catch(err=>{ 90 console.log("搜索失败",err); 91 }) 92 }, 93 94 //点击增加菜品数量 95 add(e){ 96 console.log("点击了加",e.currentTarget.dataset.id); 97 let id = e.currentTarget.dataset.id 98 //购物车菜品信息 99 let cartList = this.data.cartList 100 //遍历当前菜品数组 101 foodList.forEach(item=>{ 102 if(item._id==id){ 103 item.number+=1 104 //购物车所选菜品的信息 105 if(cartList&&cartList.length>0){ //如果购物车中有数据 106 //检查当前购物车里是否存在当前所选的菜品 107 var res = cartList.find(cart=>{ 108 return cart._id == id 109 }) 110 console.log("当前所选的菜品是否存在于购物车里",res); 111 console.log("+++以后购物车的菜品列表",cartList); 112 //如果所选的菜品不在购物车里,直接添加到数组 113 if(!res){ 114 cartList.push(item) 115 }else{ 116 res.number = item.number 117 } 118 }else{ //如果购物车中无数据,直接push到数组 119 cartList.push(item) 120 } 121 } 122 }) 123 console.log("遍历以后的当前菜品列表",foodList); 124 console.log("添加到购物车的菜品列表",cartList); 125 this.setData({ 126 //点击添加之后的菜品列表信息 127 foodList:foodList, 128 //购物车所选商品列表 129 cartList:cartList 130 }) 131 //调用自定义方法,计算购物车总数量和总价格 132 this.getTotal() 133 //将数据存入缓存 134 wx.setStorageSync('cart', cartList) 135 }, 136 137 //点击减少菜品数量 138 minus(e){ 139 console.log("点击了减",e.currentTarget.dataset.id); 140 let id = e.currentTarget.dataset.id 141 //购物车菜品信息 142 let cartList = this.data.cartList 143 //遍历当前菜品数组 144 foodList.forEach(item=>{ 145 if(item._id==id){ 146 if(item.number>0){ 147 item.number-=1 148 //购物车所选菜品的信息 149 if(cartList&&cartList.length>0){ //如果购物车中存在已选菜品 150 //查询当前购物车里是否存在当前所选的菜品 151 var index = cartList.findIndex(cart=>{ 152 return cart._id == id 153 }) 154 if(index>-1){ 155 cartList[index].number = item.number 156 } 157 if(item.number == 0){ 158 cartList.splice(index,1) //删除下标为index的1个元素 159 } 160 } 161 }else{ 162 wx.showToast({ 163 title: '数量不能小于0', 164 icon:'none' 165 }) 166 } 167 } 168 }) 169 console.log("遍历以后的当前菜品列表",foodList); 170 console.log("---以后购物车的菜品列表",cartList); 171 this.setData({ 172 foodList:foodList, 173 //购物车所选商品列表 174 cartList:cartList 175 }) 176 //调用自定义方法,计算购物车总数量和总价格 177 this.getTotal() 178 //将数据存入缓存 179 wx.setStorageSync('cart', cartList) 180 }, 181 182 //自定义,计算购物车的总价格和总数量 183 getTotal(){ 184 //购物车的总数量、总金额、购物车菜品信息 185 let totalNumber = 0 186 let totalMoney = 0 187 let cartList = this.data.cartList 188 cartList.forEach(item=>{ 189 totalNumber+=item.number 190 totalMoney+=item.number*item.price 191 }) 192 this.setData({ 193 totalNumber:totalNumber, 194 totalMoney:totalMoney 195 }) 196 }, 197 198 //打开购物车蒙层 199 showCart(){ 200 this.setData({ 201 isHideMask:false 202 }) 203 }, 204 //关闭购物车蒙层 205 hideCart(){ 206 this.setData({ 207 isHideMask:true 208 }) 209 }, 210 211 //清空购物车 212 clearCart(){ 213 //把菜品列表所有菜品的数量置于0 214 let foodList = this.data.foodList //把菜品数据取出来 215 foodList.forEach(item=>{ //遍历数组,把每个数量设为0 216 item.number =0 217 }) 218 //把购物车数组设为空数组 219 this.setData({ 220 foodList:foodList, 221 cartList:[], 222 totalNumber:0, 223 totalMoney:0 224 }) 225 //清空购物车缓存数据 226 wx.setStorageSync('cart', null) 227 }, 228 })
三、效果展示