项目实战-点餐小程序-23 点餐(购物车)

一、功能需求

  • 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 })

三、效果展示

 

 

posted @ 2021-08-17 17:04  AnnLing  阅读(1633)  评论(0编辑  收藏  举报