第一步:项目配置
1.编写app.json
(1).pages:配置所有页面路径(必须),所有页面都需要在此列出,如果没有列出它就会报找不到某某文件路径。
(2)window: 配置窗口,配置导航及窗口的背景颜色和文字颜色,还有导航文字是否可以下拉刷新。
(3)subPackages:分包配置
(4)tabBar: tab栏配置,配置tab栏背景色及出现位置,上边框的颜色(目前只支持黑或白),文字颜色及文字选中颜色,最核心的配置是list即tab栏的列表,官方规定最少2个,最多5个,每个列表项目可配置页面路径、文字、图标及选中时图标的地址

二.确定目录结构
- image --图片
- pages --页面
- index --页面文件夹 ("index"为自定义的页面名称,页面相关文件的文件名需与页面名相同)
- index.js-- 页面逻辑
- index.wxml --页面结构
- index.json --页面配置 (可以参考 app.json里面的window窗口配置)
- index.wxss --页面样式
- index --页面文件夹 ("index"为自定义的页面名称,页面相关文件的文件名需与页面名相同)
- app.js - 小程序整体逻辑 (初始化、显示、隐藏的事件,以及存放全局数据)
- app.json - 小程序公共配置
- app.wxss - 小程序公共样式
- weui --引用weui 样式
- weui.wxss --weui样式
第二步:编写页面
index首页
- index.json
配置窗口标题以及下拉刷新

- index.wxml
用view(视图容器)进行布局
<view class='car-container'>
<!-- 顶部信息 -->
<view class='car-top'>
<view class='title'>购物车 {{userInfo}}</view>
<view class='btn-edit'>{{cargoods.length}}件</view>
</view>
<!-- 购物车列表 -->
<view class='car-list'>
<!-- 购物车产品 -->
<view class='car-item' wx:for='{{cargoods}}'>
<!--列表项,总长度为按钮的宽度50px+goods-info的长度 -->
<view class='car-prod' data-index='{{index}}' style='left:{{moveLength[index]}}px;width:{{windowWidth+30}}px;' bindtouchend='moveEnd' bindtouchstart='moveStart' bindtouchmove='moving' bindtouchcancel='moveEnd'>
<!-- 商品信息 左边有20px的填充,所以需要减去20 -->
<view class='goods-info {{item.isBuy?"active":""}}' data-index='{{index}}' catchtap='toggleBuy' style='width:{{windowWidth-20}}px;'>
<view class='goods-info-inner'>
<view class='checkbox'></view>
<view class='goods-image'>
<image src='{{item.pic}}'></image>
</view>
<view class='good-info'>
<view class='name'>{{item.name}}</view>
<view class='footer'>
<view class='price'>¥{{item.price}}</view>
<view class='numbers'>
<view class='number-box'>
<view class='controler left' data-index='{{index}}' catchtap='reduceNumber'>-</view>
<view class='controler middle'>{{item.numbers}}</view>
<view class='controler right' data-index='{{index}}' catchtap='addNumber'>+</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class='btn-delete' data-index='{{index}}' catchtap='removeGoods'>删除</view>
</view>
</view>
<!-- 没有商品信息 -->
<view wx:if='{{cargoods.length==0}}'>
<navigator url='/pages/index/index' open-type='switchTab' style='padding:100rpx 20rpx;'>
购物车空空如也,赶紧去挑选你心意的产品吧~~~~~
</navigator>
</view>
</view>
<!-- 购物车底部 -->
<view class='car-footer-container'>
<view class='car-footer'>
<view class='select-all {{selectAll?"active":""}}' catchtap='checkAll'>全选</view>
<view class='btn-buy'>
<text style='color:red;padding:0 10px;'>合计:¥{{totalPrice}}</text>
<button type='warn' disabled='{{totalPrice==0}}' catchtap='deleteAll'>去结算</button>
</view>
</view>
</view>
</view>
- shopcar.wxss
/* 购物车顶部信息 */
.car-top {
background-color: #efefef;
height: 80rpx;
line-height: 80rpx;
padding: 0 20rpx;
}
.car-top .btn-edit {
float: right;
}
.car-top .title {
float: left;
}
/* 商品列表项 */
.car-list {
padding-bottom: 47px;
}
.car-item {
position: relative;
padding-left: 20px;
overflow: hidden;
}
.car-item .car-prod {
border-bottom: 1px solid #ddd;
position: relative;
left: 0;
box-sizing: border-box;
overflow: hidden;
}
.car-prod .btn-delete {
float: left;
border-radius: 0;
font-size: 30rpx;
box-sizing: border-box;
width: 50px;
background-color: #e64340;
color: #fff;
text-align: center;
height: 260rpx;
line-height: 260rpx;
}
.goods-info {
float: left;
box-sizing: border-box;
background: url(https://cdn.it120.cc/images/weappshop/gou.png) no-repeat 30rpx center;
background-size: 40rpx auto;
}
.goods-info.active {
background-image: url(https://cdn.it120.cc/images/weappshop/gou-red.png);
}
.goods-info .goods-info-inner {
display: flex;
padding: 40rpx 0;
}
.goods-info-inner .checkbox {
width: 120rpx;
}
.goods-info-inner .goods-image {
width: 180rpx;
height: 180rpx;
}
.goods-info-inner .goods-image image {
width: 180rpx;
height: 180rpx;
display: block;
}
.goods-info-inner .good-info {
flex: 1;
padding: 0 20rpx;
}
.goods-info-inner .good-info .name {
width: 380rpx;
height: 90rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 10rpx 0;
box-sizing:border-box;
}
.goods-info-inner .good-info .price {
float: left;
color: #e64340;
}
.goods-info-inner .good-info .numbers {
float: right;
}
.goods-info-inner .good-info .footer {
height: 90rpx;
line-height: 90rpx;
}
/* 购物车底部 */
.car-footer-container {
background-color: #efefef;
border-top: 1px solid #ddd;
position: fixed;
bottom: 0;
width: 100%;
}
.car-footer {
display: flex;
}
.car-footer .select-all {
background: url(https://cdn.it120.cc/images/weappshop/gou.png) no-repeat 60rpx center;
background-size: 40rpx auto;
text-align: right;
height: 46px;
line-height: 46px;
padding-left: 120rpx;
}
.car-footer .select-all.active{
background-image: url(https://cdn.it120.cc/images/weappshop/gou-red.png);
}
.car-footer .btn-buy {
flex: 1;
text-align: right;
}
.car-footer .btn-buy button {
display: inline-block;
vertical-align: middle;
border-radius: 0;
}
/*商品购买数量*/
.number-box{
display: flex;
}
.number-box .controler{
padding: 0px 8px;
height: 60rpx;
line-height:60rpx;
background-color: #efefef;
border: 1px solid #ddd;
}
.number-box .controler.middle{
background-color: #fff;
text-align: center;
border-left: none;
border-right: none;
padding: 0 10px;
}
.number-box .controler.left{
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.number-box .controler.right{
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}- shopcar.js 逻辑处理
使用https引入图片路径
数据表明:bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡
// pages/shopcar/shopcar.js
Page({
data: {
moveLength: [0, 0, 0, 0], //移动的长度
moveStartX: [0, 0, 0, 0], //x轴移动的起点
windowWidth: 0, //窗体的宽度
cargoods: [], //购物车信息
totalPrice: 0, //总价
selectAll: false, //是否全选
userInfo: '', //用户信息
},
//移动开始
moveStart(e) {
var index = e.currentTarget.dataset.index;
var key = "moveStartX[" + index + "]"
this.setData({
//这个地方的算法有点复杂,当前坐标pageX+当前的元素移动的位置moveLength,才能保证同步移动,要考虑元素的偏移量
[key]: e.touches[0].pageX - this.data.moveLength[index]
});
},
//移动中
moving(e) {
var index = e.currentTarget.dataset.index;
var key = "moveLength[" + index + "]"
//获取移动的距离
var length = e.changedTouches[0].pageX - this.data.moveStartX[index];
this.setData({
[key]: length
});
},
//移动结束
moveEnd(e) {
var index = e.currentTarget.dataset.index;
var key = "moveLength[" + index + "]"
//最终移动的长度
var len = e.changedTouches[0].pageX - this.data.moveStartX[index]
//向左移动超过了50px
if (len < -50) {
len = -50; //显示删除按钮
} else if (len == 0 || this.data.moveLength[index] == -50) {
//由于点击时也会触发 bindtouchstart和bindtouchend事件,此时很有可能没有移动或是moveLength初始值-50的情况
//这种情况不做任何的操作
return;
} else {
len = 0; //隐藏删除按钮
}
this.setData({
[key]: len
});
},
onLoad: function (options) {
var app = getApp();
//获取全局的数据
var globalData = app.globalData;
console.log(globalData.cargoods)
var sysInfo = wx.getSystemInfoSync();
this.setData({
windowWidth: sysInfo.windowWidth,
cargoods: globalData.cargoods //将全局数据,赋值本地变量,方便后面的操作
})
this.setData({
totalPrice: this.totalPrice()
})
},
//总价计算
totalPrice() {
var tempGoods = this.data.cargoods;
var totalPrice = 0;
totalPrice = tempGoods.reduce(function (total, current) {
if (current.isBuy) {
return total + current.price * current.numbers;
} else {
return total;
}
}, 0)
return parseFloat(totalPrice.toFixed(2))
},
//减少数量
reduceNumber(e) {
var index = e.currentTarget.dataset.index //获取下标
var goods = this.data.cargoods[index];
if (goods.numbers == 1) {
return;
}
var key = 'cargoods[' + index + '].numbers';
this.setData({
[key]: goods.numbers - 1, // [key] 是 es5中的计算属性命名,将变量的内容作为key
})
this.setData({
totalPrice: this.totalPrice()
})
},
//增加数量
addNumber(e) {
var index = e.currentTarget.dataset.index //获取下标
var goods = this.data.cargoods[index];
var key = 'cargoods[' + index + '].numbers';
this.setData({
[key]: goods.numbers + 1, // [key] 是 es5中的计算属性命名,将变量的内容作为key
})
this.setData({
totalPrice: this.totalPrice()
})
},
//选择或取消购买
toggleBuy(e) {
var index =e.currentTarget.dataset.index //获取下标
var goods = this.data.cargoods[index];
var key = 'cargoods[' + index + '].isBuy';
//只要有一个没有选中,全选取消
if (goods.isBuy) {
this.setData({
selectAll: false
})
}
//设置购买状态
this.setData({
[key]: !goods.isBuy, // [key] 是 es5中的计算属性命名,将变量的内容作为key
})
//重新计算总价
this.setData({
totalPrice: this.totalPrice()
})
},
//全选,全不选
checkAll(e) {//全选
var checked = !this.data.selectAll;
this.setData({
selectAll: checked
})
var goods = this.data.cargoods;
var len = goods.length;
for (var i = 0; i < len; i++) {
var key = 'cargoods[' + i + '].isBuy';
this.setData({
[key]: checked, // [key] 是 es5中的计算属性命名,将变量的内容作为key
})
}
//重新,计算总价
this.setData({
totalPrice: this.totalPrice()
})
},
//删除商品
removeGoods(e) {
var index = e.currentTarget.dataset.index //获取下标
var goods = this.data.cargoods;
goods.splice(index, 1)
this.setData({
cargoods: goods
})
// 删除后重新计算总价
this.setData({
totalPrice: this.totalPrice()
})
console.log(index, goods);
},
//结算 ,不管选没选的清除
deleteAll(e){
var index = e.currentTarget.dataset.index //获取下标
var goods = this.data.cargoods;
goods.splice(index)
this.setData({
cargoods: goods
})
}
})
常用的:
1.使用竖向滚动时,需要给scroll-view一个固定高度,通过 WXSS 设置 height。如果scroll-view高度设置为100%,则不能触发上拉刷新和下拉加载事件......
2.image背景图片地址必须是url或者base64/本地资源无法通过 css 获取 可以使用网络图片,或者 base64,或者使用 标签