弹出式购物车组件
秋天已经来啦,奶茶还会远吗?家人们!有没有给自己点秋天的第一杯奶茶捏~
在很多线上点单的小程序或者购物软件中,我们经常可以看到这种弹出式购物车。
有没有小伙伴疑问这个东东是怎么做出来的呢?相信这篇文章会给你启发,请继续往下看吧!
1. 组件业务说明
- 购物袋样式是下方的功能条,显示了用户选择的总数和总金额,只有在用户选择了某个奶茶后,下方的购物袋才会出现,当然,取消所有奶茶订单后,它又会消失不见;当然!完成订单后你的余额也会消失不见(微笑)!
- 点击购物袋会弹出奶茶详情,用户可以对点单信息进行数据操作,例如清空、加一和减一,在这些操作下,购物袋的数量和总额数据做出相应的数据更新。其实你也可以不用减少和清空功能,只能加单,这样的话,可刑!可拷!
- 点击灰色空白处可退出购物车详情,即可回到店铺页面,如果没有任何订单,购物袋消失。
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 奶茶信息展示的弹性布局
每个奶茶的展示窗口都是左边是图片,右边是描述信息的布局,所以,我们先用一个大盒子(类名为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
标签,设置一个固定高度,里面的子盒子超过高度就可实现滚动,保证了数据的完整展示。
3.3 购物袋详情空白处退出
在购物详情是没有退出按钮的,只有当点击空白处,才能返回商店。为了做出这个效果,我们设置最大的盒子为弹性布局display: flex
,先确定数据详情部分高度,再设定上方空白盒子为wxss样式为flex: 1
,这样空白盒子可以填满剩余高度,再调整一下空白盒子颜色。之后再添加点击quit
方法,就可以达到预定效果啦。
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事件,当用户点击加号或减号按钮时触发addNum
和sunNum
方法,与退出(quit
)不同的是,这两个方法需要传参即传输数组下标,才能对相应的奶茶数据进行修改,所以三个步骤传数组下标数据:
- 组件数据传输:步骤一:我们需要在组件循环输出
orders
数据时偷偷埋下一个下标数据data-index
;
步骤二:在method
中先取得下标数据,再用this.triggerEvent
方法中通过第二个参数传输,即传输给父页面的信息mes
( string类型 );
步骤三:在父页面的js文件方法中,通过parseInt()
方法就把String
转为Int
得到我们想要的下标数据index
;
-
具体的数据操作:为了数据的快速响应和解决业务异步问题,我们的数据需要先存储在页面
data
中,在某个触发事件时,例如前往支付界面等,再把数据更新到云数据库中。所以我们减少数量操作只需要修改data
里的orders
数组的对应下标对象内的num
(杯数)值、orderNumber
(订单总数)和totalPrice
(总金额)数据,在数据修改后,用户点击减单后需要判断orders
对象数组的杯数num是否为0,如果为0,用数组的splice
方法将该对象从数组中移除;这个时候就和退出quit
配套使用了,orders长度为0时,退出时购物袋消失。加单的话,不用作判空操作,其他操作与减类似。 -
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 中获取。
感谢大家的观看❤!!!