2019独角兽企业重金招聘Python工程师标准>>>
效果图
包含以下模块
- 选购页实现切换分类与数量加减
- 购物车动画与同步数量加减
- 购物车弹窗自适应商品条数
一、 点击分类项,切换右边的食品,并高亮自身
这个实现比较简单,给一个states数组,用于记录每一项分类的状态,点击设为true,wxml渲染时三目运算判断即可。
categoryStates = categoryStates.map(function (item, i) {
if (index == i) {
item = true;
} else {
item = false;
}
return item;
});
相应的wxml文件,class="{{categoryStates[index] ? 'category-item-active' : ''}}"
二、 加减按钮
- 初始只有一个加号
- 点击加号后,相应商品数量+1,并出现减号
- 减至0时,减号消失,连同数量值
设计数组结构
cartData: {},它的键是Food表的objectId,值是数量。
以下是js代码实现
add: function (e) {
// 所点商品id
var foodId = e.currentTarget.dataset.foodId;
console.log(foodId);
// 读取目前购物车数据
var cartData = that.data.cartData;
// 获取当前商品数量
var foodCount = cartData[foodId] ? cartData[foodId] : 0;
// 自增1后存回
cartData[foodId] = ++foodCount;
// 设值到data数据中
that.setData({
cartData: cartData
});
}
在wxml文件中绑定数据如下
-
{{cartData[item.objectId]}}
+
上述代码中,通过wx:if判断当前商品的数量是否存在,无则不显示减号按钮;而在加号按钮旁要显示的数量就是{{cartData[item.objectId]}}
;点击事件传递的foodId就是{{item.objectId}}
减法按钮类似
subtract: function (e) {
// 所点商品id
var foodId = e.currentTarget.dataset.foodId;
// 读取目前购物车数据
var cartData = that.data.cartData;
// 获取当前商品数量
var foodCount = cartData[foodId];
// 自减1
--foodCount;
// 减到零了就直接移除
if (foodCount == 0) {
delete cartData[foodId]
} else {
cartData[foodId] = foodCount;
}
// 设值到data数据中
that.setData({
cartData: cartData
});
}
三、购物车动画
cascadeToggle: function () {
//切换购物车开与关
if (that.data.maskVisual == 'show') {
that.cascadeDismiss();
} else {
that.cascadePopup();
}
},
cascadePopup: function () {
// 购物车打开动画
var animation = wx.createAnimation({
duration: 500,
timingFunction: 'ease-in-out',
});
this.animation = animation;
animation.translateY(-285).step();
this.setData({
animationData: this.animation.export(),
maskVisual: 'show'
});
},
cascadeDismiss: function () {
// 购物车关闭动画
this.animation.translateY(285).step();
this.setData({
animationData: this.animation.export(),
maskVisual: 'hidden'
});
}
通过点击控制显示与隐藏,
而
四、购物车加减
首先要读取购物车数据,即cartData,它是以foodId为key,数量为value的object,所以需要转换为array,才能很好地被遍历。
cartToArray: function (foodId) {
// 需要判断购物车数据中是否已经包含了原商品,从而决定新添加还是仅修改它的数量
var cartData = that.data.cartData;
var cartObjects = that.data.cartObjects;
var query = new Bmob.Query('Food');
// 查询对象
query.get(foodId).then(function (food) {
// 从数组找到该商品,并修改它的数量
for (var i = 0; i < cartObjects.length; i++) {
if (cartObjects[i].food.id == foodId) {
// 如果是undefined,那么就是通过点减号被删完了
if (cartData[foodId] == undefined) {
delete cartObjects[i];
} else {
cartObjects[i].quantity = cartData[foodId];
}
that.setData({
cartObjects: cartObjects
});
// 成功找到直接返回,不再执行添加
return ;
}
}
// 添加商品到数组
var cart = {};
cart.food = food;
cart.quantity = cartData[foodId];
cartObjects.push(cart);
that.setData({
cartObjects: cartObjects
});
});
}
然后在add/subtract方法末尾中调用它就可以购物车键值对转换成对象数组。
那接下来就顺理成章了,直接购物车小弹窗里将cartObjects渲染就可以了。
{{item.food.title}}
{{item.food.price * item.quantity}}
-
{{cartData[item.food.objectId]}}
+
得益于MVVM数据绑定,因此在购物车里点加减也实时地同步了商品列表中显示的数量
汇总
amount: function() {
var cartObjects = that.data.cartObjects;
var amount = 0;
cartObjects.forEach(function (item, index) {
amount += item.quantity * item.food.get('price');
});
that.setData({
amount: amount
});
}
这里多请求了一次网络,由于请求是异步的,所以我将汇总代码丢在网络请求里,于cartToArray
方法内。
减法与加法基本类似,值得一提的是,减法要判断非负的合法性,所以将自减至零时,直接将元素通过delete操作移除,省去后续提交购物车遍历汇总的非零判断的烦琐。
五、购物车高度自适应
购物车列表用的是view作为容器,这样列表是不能在弹窗里滚动的,因此要将购物车弹窗改为scroll-view显示,并且高度自适应行数,直至一个max-height高度
改造
替换成
,同时在样式表中为它增加一个高度height值。
bug
过程出现了一个bug,外部的商品列表上拉时再触发购物车弹窗会出现有白屏区块。
在wxml面板查看,发现是modal-mask层随着页面滚动而上移了
果断修改样式.modal-mask {position: absolute;}
为.modal-mask {position: fixed;}
问题迎刃而解。
进一步改造
将高亮动态化,由wxss样式转移到.js代码中控制
1、先注释掉wxss中硬编码的height样式
/*弹窗主体*/
.modal-content {
position: fixed;
bottom: -235px;
left: 0;
width: 100%;
/*height: 235px;*/
margin-top: 5px;
background: #fff;
z-index: 99;
}
/*内容区域*/
.modal-body {
font-size: 14px;
/*height: 145px;*/
max-height: 295px;
}
2、在js文件声明成员变量
// 最大行数
var max_row_height = 5;
// 行高
var cart_footer_offset = 90;
// 底部栏偏移量
var food_row_height = 49;
设定最大行数,是因为这个弹窗不能无限伸展,否则都盖过整个屏幕了;在最大行数以内,都应该自动适应高度。
3、计算高度值
// scrollHeight为商品列表本身的高度
var scrollHeight = (that.data.cartObjects.length <= max_row_height ? that.data.cartObjects.length : max_row_height) * food_row_height;
// cartHeight为整个购物车的高度,也就是包含了标题栏与底部栏的高度
var cartHeight = scrollHeight + cart_offset;
animation.translateY(- cartHeight).step();
that.setData({
scrollHeight: scrollHeight,
cartHeight: cartHeight
});
4、wxml绑定数据
...
到此不论购物车内有几条数据,都能很好的自适应;超过5条,开始滚动视图,大功告成。
源码下载:http://git.oschina.net/laeser/dinner,或者关注公众号【黄秀杰】,回复112。