来一杯奶茶,陪你写购物车组件

1,263 阅读7分钟

弹出式购物车组件

秋天已经来啦,奶茶还会远吗?家人们!有没有给自己点秋天的第一杯奶茶捏~

emo1.jpg

在很多线上点单的小程序或者购物软件中,我们经常可以看到这种弹出式购物车。

pic.png

有没有小伙伴疑问这个东东是怎么做出来的呢?相信这篇文章会给你启发,请继续往下看吧!

emo3.jpg

1. 组件业务说明

  • 购物袋样式是下方的功能条,显示了用户选择的总数和总金额,只有在用户选择了某个奶茶后,下方的购物袋才会出现,当然,取消所有奶茶订单后,它又会消失不见;当然!完成订单后你的余额也会消失不见(微笑)!

演示1.gif

  • 点击购物袋会弹出奶茶详情,用户可以对点单信息进行数据操作,例如清空、加一和减一,在这些操作下,购物袋的数量和总额数据做出相应的数据更新。其实你也可以不用减少和清空功能,只能加单,这样的话,可刑!可拷!

演示2.gif

  • 点击灰色空白处可退出购物车详情,即可回到店铺页面,如果没有任何订单,购物袋消失。

演示3.gif

2. 组件数据处理

第一, 要实现购物袋随订单的状态而出现和消失的效果, 我们需要用到一个Boolean类型变量isCar,在每次订单状态发生改变时,方法对订单对象数组的长度进行判断,之后再通过this.setData设置isCar的值;通过block标签判断isCar的值,达到购物袋显示效果。

  <block wx:if="{{isCar}}">
  // 购物详情
  <panel orders="{{orders}}"/>
  // 购物袋
  <view class="car" bindtap="gotoDetail"> 
    <view class="null">
    <view class="shopBag">
      <image src="/assets/images/shopBag.png"></image>
    </view>
    <view class="number">{{orderNumber}}</view>
    <view class="total-price">¥{{totalPrice}}</view>
    <view class="sure-button" bindtap="gotoPay">选好了</view>
    </view>
  </view>
  </block>

第二,为了数据匹配,我们在每种奶茶的选购按钮中,绑定了点击事件,并在标签中通过data-传输了相应奶茶的数据,以便后续的数据传递和数据操作。

<view class="product-button" 
                  bindtap="car" 
                  data-price="{{items.price}}"
                  data-pic="{{items.pic}}"
                  data-desc="{{items.desc}}"
                  data-title="{{items.title}}"
                  data-num="{{1}}">选购</view>

第三,组件需要显示奶茶详情信息,我们就需要将目前你已经点的奶茶的订单数据orders传输到组件中,由于实时操作对数据修改,我们只需要用this.setData对页面orders里的数据进行修改,在组件中通过循环就可以输出实时的点单数据。

<panel orders="{{orders}}"/>

3.组件布局设计亮点

在这个组件的布局中,有3个值得提醒的地方:

1.弹性布局
2.数据展示
3.空白处退出

3.1 奶茶信息展示的弹性布局

image.png

每个奶茶的展示窗口都是左边是图片,右边是描述信息的布局,所以,我们先用一个大盒子(类名为drink)将一个奶茶所有信息包起来,再将右侧详细信息另外用一个盒子(类名drink_desc)装起来,与图片image同级。drink类设置为弹性布局,这样我们只要设置图片的宽度,drink_desc就会填充剩余的宽度。由于右侧drink_desc的信息是列的形式展开,所以我们用到了一个好用的样式flex-direction: column;:让盒子内子盒子纵向排列,然后调整信息显示格式即可。具体代码:

// 组件部分wxml
<view class="drink" wx:for="{{orders}}" wx:key="index" wx:for-item="order">
      <image src="{{order.pic}}"></image>
      <view class="drink_desc">
        <view class="title">{{order.title}}</view>
        <view class="tags">{{order.desc}}</view>
        <view class="price">¥{{order.price}}</view>
        <view class="adjustQuantity">
          <view class="subtracts" bindtap="subNum" data-index="{{index}}">
            <image src="../../assets/icons/subtracts.png"></image>
          </view>
          <view class="num" data-num="{{order.num}}">{{order.num}}</view>
          <view class="add" bindtap="addNum" data-index="{{index}}">
            <image src="../../assets/icons/add.png"></image>
          </view> 
        </view>
      </view>
      </view>
// wxss
.drink {
  position: relative;
  height: 180rpx;
  width: 80%;
  padding: 10rpx 40rpx;
  display: flex;
  align-items: center;
  border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
  margin-left: 5%;
}
.drink_desc {
  margin-left: 20rpx;
  display: flex;
  line-height: 40rpx;
  flex-direction: column;
}

3.2 过长数据scroll-view展示

由于购物详情一直在页面底部,且高度固定,所以当产品过多,无法全部展示。这时,我们就可以使用微信的srcoll-view标签,在需要滚动的地方加一个srcoll-view标签,设置一个固定高度,里面的子盒子超过高度就可实现滚动,保证了数据的完整展示。

image.png

3.3 购物袋详情空白处退出

在购物详情是没有退出按钮的,只有当点击空白处,才能返回商店。为了做出这个效果,我们设置最大的盒子为弹性布局display: flex,先确定数据详情部分高度,再设定上方空白盒子为wxss样式为flex: 1,这样空白盒子可以填满剩余高度,再调整一下空白盒子颜色。之后再添加点击quit方法,就可以达到预定效果啦。 -60f3e671a3a60efb..jpg

4. 组件业务逻辑

1. 组件出场方式

我们在购物袋标签中绑定一个点击事件gotoDetail(),这个时候我们需要用到组件的selectComponent选择器,这个选择器会根据ID获取组件对象,所以我们需要给组件设一个ID,获取到这个组件之后就可以调用它自己在method中的shopBag方法。

shopBag()方法的作用就是将Boolean类型变量flag赋值为false。 (这里就要说到变量flag的作用啦,为了达到组件消失的效果,我们在组件的最外层标签中添加了hidden="{{flag}}",只要flag设为 false 时,组件就会出现,当然,flag的初值为 true。

<view class="page" hidden="{{flag}}">
// 组件标签
<panel orders="{{orders}}" id="panel"/>

// gotoDetail()方法
gotoDetail() {
    this.panel = this.selectComponent('#panel');
    this.panel.shopBag();
  }
// 组件中method中的shopBag()方法
shopBag() {
      this.setData({
        flag: false
      })
    }

2 组件空白处退出

同理,消失就是在组件的空白区域标签上绑定一个quit()方法,去设置flag的值为 true 即可做到组件消失。但是,还有一个问题,即当用户在详情页时,把购物袋里商品清空或总减为零时,购物袋orders的长度为0,这是购物袋应该消失,所以我们在退出后应判断orders的长度,如果为0,则将isCar赋值为为false,购物袋消失。于是我们就在组件标签上加了一个组件事件 quit(),组件中quit方法中需要添加 this.triggerEvent("quit")quit为组件标签中的 bind的名称。

// 组件method中quit()
quit() {
      this.triggerEvent("quit");
      this.setData({
        flag: true
      })
    }
   
// index.js 中quit()
quit(){
      if(this.data.orders.length == 0){
        this.setData({
          isCar: false
        })
      }
    }
    
// 组件
<panel orders="{{orders}}" id="panel" bind:quit="quit"/>

3. 组件数据操作

在详情页中可进行数量的增减和清空操作。

1. 增减

由于增加和减少的数据操作相似,且减少数据操作更复杂一些,所以我们重点讲解减操作。减少订单是点击组件中的按钮时触发,由于数据组件没有直接参与数据的存储,只是做一个数据的展示,所以我们仍然需要在组件标签中添加add和sub事件,当用户点击加号或减号按钮时触发addNumsunNum方法,与退出(quit)不同的是,这两个方法需要传参即传输数组下标,才能对相应的奶茶数据进行修改,所以三个步骤传数组下标数据:

  1. 组件数据传输:步骤一:我们需要在组件循环输出orders数据时偷偷埋下一个下标数据data-index
    步骤二:在method中先取得下标数据,再用this.triggerEvent方法中通过第二个参数传输,即传输给父页面的信息mes( string类型 );
    步骤三:在父页面的js文件方法中,通过parseInt()方法就把String转为Int得到我们想要的下标数据index

-4ed0f6abced0f84e..jpg

  1. 具体的数据操作:为了数据的快速响应和解决业务异步问题,我们的数据需要先存储在页面data中,在某个触发事件时,例如前往支付界面等,再把数据更新到云数据库中。所以我们减少数量操作只需要修改data里的orders数组的对应下标对象内的num(杯数)值、orderNumber(订单总数)和totalPrice(总金额)数据,在数据修改后,用户点击减单后需要判断orders对象数组的杯数num是否为0,如果为0,用数组的splice方法将该对象从数组中移除;这个时候就和退出quit配套使用了,orders长度为0时,退出时购物袋消失。加单的话,不用作判空操作,其他操作与减类似。

  2. tips : 在es6中,用this.setData({})赋值,当方法中变量名与data中变量名相同时,可只写data中被赋值变量,增强代码可读性。

<panel orders="{{orders}}"  
    id="panel" 
    bind:add="addNum" 
    bind:sub="subNum" 
    bind:clearAll="clearAll"
    bind:quit="quit"/>
    
// method中addNum和subNum()
addNum(e) {
      let index = e.currentTarget.dataset.index;
      this.triggerEvent("add", {mes:index})
    },
    subNum(e) {
      let index = e.currentTarget.dataset.index;
      this.triggerEvent("sub", {mes:index})
    } 
    
// 父页面js中addNum和subNum方法
subNum(e) {
      let index = parseInt(e.detail.mes);
      let orders = this.data.orders;
      let orderNumber = this.data.orderNumber;
      let totalPrice = this.data.totalPrice;
      --orders[index].num;
      --orderNumber;
      totalPrice = totalPrice - parseInt(orders[index].price);
      if(orders[index].num == 0){
        orders.splice(index, 1);
      }
      this.setData({orders,orderNumber,totalPrice});
    }

2. 清空

购物袋清空相较于加减更加简单,但也是需要用到组件方法,也是通过this.triggerEvent("clearAll")实现的,但是不需要传输具体数据,直接将总额,总杯数设置为0,并清空orders数组。

clearAll(){
      let orders = this.data.orders;
      let orderNumber = 0;
      let totalPrice = 0;
      orders = [];
      this.setData({isCar:true, orders,orderNumber,totalPrice})
    }

至此,这个组件的基本功能都实现啦!详细项目代码请到 Gitee 中获取。

感谢大家的观看❤!!!

-4e972d375dbc7f25..jpg