项目是基于uview2.0的ui组件,并且在一定程度上修改过原本组件的代码(app-navbar是使用u-navbar在进行二次封装的组件;u-number-box也进行了修改),符合项目需求(这个看个人项目需求在进行修改)
u-number-box有点难用的地方,加减有时候不能很及时的回应合计的数量,导致总价对不上,所以我开启了asyncChange(是否开启异步变更,开启后需要手动控制输入值)。
u-number-box一些改动到的地方
this.$emit(type) 改成 this.$emit(type,value) type是minus和plus
onInput(){
...
if (this.asyncChange) {
this.$nextTick(() => {
this.currentValue = formatted
this.$forceUpdate()
})
}
this.$emit('input', formatted)
//以上时新增加
}
<!-- 购物车 -->
<template>
<view>
<!-- 说明:因为小程序右上角有胶囊会挡住右上角的“管理”按钮,所以给设置到左边,app还是在右上角 -->
<!-- #ifndef MP -->
<app-navbar navTitle="购物车" bgColor="#fff" leftIconColor="#000" :rightText="manageIndex == 0 ? '管理' : '退出管理'" :border="false" @right="manage"></app-navbar>
<!-- #endif -->
<!-- #ifdef MP -->
<app-navbar navTitle="购物车" bgColor="#fff" leftIconColor="#000" :leftText="manageIndex == 0 ? '管理' : '退出管理'" :border="false" @leftText="manage"></app-navbar>
<!-- #endif -->
<view class="trolley-list">
<view class="trolley-item" v-for="(item,index) in trolleyList" :key="index">
<view class="item-store flex align-c">
<u-image :src="item.check ? checkYes : checkNo" width="42rpx" height="42rpx" @click="changeItemCheck(item)"></u-image>
<view class="store-icon">
<u-image src="./trolleyStoreIcon.png" width="42rpx" height="42rpx"></u-image>
</view>
<view class="store-title f32 text-medium col-1e3 text-over1">
仙灵老酒坊仙灵老酒坊仙灵老酒坊
</view>
<view class="store-right">
<u-image src="./trolleyStoreRight.png" width="34rpx" height="34rpx"></u-image>
</view>
</view>
<view class="store-list" v-for="(i,k) in item.children" :key="k">
<view class="flex align-c list-item">
<view class="list-del flex align-c justify-c" v-if="manageIndex == 1">
<view class="del-view" @click.stop="changeIDel(item,index,k)">
<u-icon name="minus-circle-fill" width="42rpx" height="42rpx" size="42rpx" color="#F43B15"></u-icon>
</view>
</view>
<view class="list-check" @click="changeICheck(i,item)">
<u-image :src="i.check ? checkYes : checkNo" width="42rpx" height="42rpx"></u-image>
</view>
<view class="list-cover">
<u-image src="./cover.png" width="200rpx" height="200rpx" radius="16rpx"></u-image>
</view>
<view class="list-msg">
<view class="list-title text-over1 f32 col-1e3 text-medium">
泸州老窖高度酒世家精品52°至尊版
</view>
<view class="list-spe text-over1 f28 col-96a text-regular">
典藏版-500ml-红色-精装-豪华-998
</view>
<view class="list-label flex">
<view class="flex align-c justify-c label-item">
<view class="col-f43 text-regular f20">
标签1
</view>
</view>
<view class="flex align-c justify-c label-item">
<view class="col-f43 text-regular f20">
标签1
</view>
</view>
</view>
<view class="list-pap flex align-c justify-sb">
<view class="col-fe5 text-bold list-pap-price">
¥{{i.price}}
</view>
<view class="pap-num flex align-c justify-c" v-if="!i.showBox" @click="showNumberBox(i,k)">
<view class="f28 text-regular col-1e3">
x{{i.quantity}}
</view>
</view>
<view class="pap-box" v-if="i.showBox">
<u-number-box :value="i.quantity" :asyncChange="true" @minus="boxChangeMinus($event,i)" @plus="boxChangePlus($event,i)" @input="boxChangeInput($event,i)" bgColorNum="#fff" :integer="true" :min="1">
<view slot="minus" class="minus">
<u-image width="42rpx" height="42rpx" :src="i.quantity <= 1 ? minusNo : minus" name="minus"></u-image>
</view>
<view slot="plus" class="plus">
<u-image width="42rpx" height="42rpx" :src="plusPay" name="plus"></u-image>
</view>
</u-number-box>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view style="margin-top: 200rpx;" v-if="trolleyList.length == 0">
<u-empty text="暂无数据" icon="./empyIcon.png"></u-empty>
</view>
<view class="kongfooter"></view>
<view class="trolley-footer flex">
<view class="flex align-c justify-sb footer-1">
<view class="flex align-c justify-c">
<u-image :src="trolleyAll ? checkYes : checkNo" width="42rpx" height="42rpx" @click="settle"></u-image>
<view class="footer-msg">
<view class="footer-msg-top f24 col-96a text-regular" v-if="allNum != 0">
已选{{allNum}}件
</view>
<view class="flex align-c">
<view class="f24 col-1e3 text-regular">
合计:
</view>
<view class="f40 col-fe5 text-bold">
¥{{allTotal}}
</view>
</view>
</view>
</view>
<view class="flex align-c justify-c trolley-btn">
<view class="f36 text-bold col-fff">
结算
</view>
</view>
</view>
</view>
</view>
</template>
<script>
//加法(mathAdd)和乘法(mathMul)的精度计算函数
import { mathAdd,mathMul} from '@/utils/mathUtils.js'
export default{
data(){
return{
trolleyAll:false,
manageIndex:0,//0管理 1退出管理
checkNo: './payNo.png',
checkYes:'./checkYes.png',
minus: './minusPay.png',
minusNo: './minusPayNo.png',
plusPay: './plusPay.png',
plusPayNo: './plusPayNo.png',
quantity:1,
trolleyList:[],
allTotal:0,//合计
allNum:0,//总件数
}
},
onLoad() {
this.getRrolleyList()
},
onReachBottom() {
},
onPullDownRefresh() {
this.getRrolleyList()
},
methods:{
//删除商品
changeIDel(item,index,k){
if(item.children.length == 1){
this.trolleyList.splice(index,1)
}else{
this.trolleyList[index].children.splice(k,1)
}
this.getTotal()
this.isAllCheck()
},
//判断是否全选
isAllCheck(){
let num = 0;
if(this.trolleyList.length == 0){
this.trolleyAll = false
}else{
this.trolleyList.forEach((item,index)=>{
if(item.check){
num ++;
}
})
if(num == this.trolleyList.length){
this.trolleyAll = true
}else{
this.trolleyAll = false
}
}
},
//全部选中、取消
settle(){
this.trolleyAll = !this.trolleyAll
this.trolleyList.forEach((item,index)=>{
item.check = this.trolleyAll
item.children.forEach((i,k)=>{
i.check = this.trolleyAll
})
})
this.getTotal()
},
//计算合计价格
getTotal(){
let sum = 0;
let num = 0;
this.trolleyList.forEach((item,index)=>{
item.children.forEach((i,k)=>{
if(i.check){
let iSum = mathMul(i.price,i.quantity)
sum = mathAdd(sum,iSum);
num ++;
}
})
})
this.allNum = num
this.allTotal = sum
},
//勾选、取消勾选每个店铺的选择
changeItemCheck(item){
item.check = !item.check
item.children.forEach((i,k)=>{
i.check = item.check
})
this.getTotal()
this.isAllCheck()
},
//勾选、取消勾选每个商品的选择
changeICheck(i,item){
i.check = !i.check
let sum = 0
item.children.forEach((i,k)=>{
if(i.check){
sum++
}
})
if(sum == item.children.length){
item.check = true
}else{
item.check = false
}
this.getTotal()
this.isAllCheck()
},
//显示每个商品的计步器
showNumberBox(i,k){
i.showBox = !i.showBox
},
//获取购物车列表
getRrolleyList(){
let arr = [
{
children:[
{
quantity:1,
price:10
},{
quantity:2,
price:99
}
]
},
{
children:[
{
quantity:6,
price:90
}
]
},
{
children:[
{
quantity:10,
price:9.9
},{
quantity:3,
price:6.6
}
]
}
]
//check是商品是否被勾选,这个值如果后端有返回就用后端返回的key
//showBox是商品是否显示加减计步器,同上
arr.forEach((item,index)=>{
this.$set(item,'check',false)
item.children.forEach((i,k)=>{
this.$set(i,'check',false)
this.$set(i,'showBox',false)
})
})
this.trolleyList = arr
uni.stopPullDownRefresh()
},
//输入框改变
boxChangeInput(e,i){
i.quantity = e
this.getTotal()
},
//商品加
boxChangePlus(e,i){
i.quantity = e
this.getTotal()
},
//商品减
boxChangeMinus(e,i){
i.quantity = e
this.getTotal()
},
//点击管理、退出管理
manage(){
this.manageIndex = this.manageIndex == 0 ? 1 : 0
},
}
}
</script>
<style lang="scss">
page {
background-color: #F6F9FF;
}
.trolley-list{
padding: 16rpx 10rpx;
.trolley-item{
width: 730rpx;
padding: 38rpx 20rpx 46rpx 20rpx;
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 16rpx;
.store-list{
padding-top: 42rpx;
.list-item{
position: relative;
.list-del{
position: absolute;
width: 80rpx;
height: 200rpx;
background: linear-gradient(to left, rgba(255,255,255,1) 0%, rgba(255,255,255,1) 80%,transparent 100%);
top: 0;
right: 0;
z-index: 10078;
.del-view{
width: 42rpx;
height: 42rpx;
}
}
}
.list-msg{
width: calc(100% - 42rpx - 20rpx - 200rpx);
padding-left: 20rpx;
.list-title{
width: 100%;
}
.list-spe{
width: 100%;
margin-top: 12rpx;
}
.list-label{
margin-top: 14rpx;
.label-item{
margin-right: 8rpx;
height: 28rpx;
padding: 0 6rpx;
border: 1rpx solid #F43B15;
border-radius: 4rpx;
background: #fff;
}
}
.list-pap{
margin-top: 18rpx;
.list-pap-price{
font-size: 40rpx;
line-height: 40rpx;
}
.pap-num{
height: 42rpx;
padding: 0 8rpx;
border: 1rpx solid #D2E2FF;
border-radius: 8rpx;
}
}
}
.list-check{
width: 42rpx;
height: 42rpx;
margin-right: 20rpx;
}
.list-cover{
width: 200rpx;
height: 200rpx;
}
}
.item-store{
.store-icon{
margin-left: 32rpx;
width: 42rpx;
height: 42rpx;
}
.store-title{
max-width: 320rpx;
margin-left: 10rpx;
}
.store-right{
width: 34rpx;
height: 34rpx;
margin-left: 4rpx;
}
}
}
}
.kongfooter{
height: calc(180rpx + env(safe-area-inset-bottom));
}
.trolley-footer{
position: fixed;
left: 0;
right: 0;
width: 750rpx;
margin: auto;
bottom:0;
height: calc(160rpx + env(safe-area-inset-bottom));
background: #fff;
padding: 0 30rpx 0 20rpx;
z-index: 10079;
.footer-1{
height: 160rpx;
width: 100%;
}
.trolley-btn{
width: 188rpx;
height: 100rpx;
border-radius: 32rpx;
background: linear-gradient(90deg, #478BFF 0%, #47C1FF 100%);
}
.footer-msg{
margin-left: 24rpx;
.footer-msg-top{
margin-bottom: 10rpx;
}
}
}
.col-1e3{
color: #1E355E;
}
.col-96a{
color: #96A1B5;
}
.col-478{
color: #478BFF;
}
.col-fff{
color: #fff;
}
.col-f43{
color: #F43B15;
}
.col-fe5{
color: #FE5502;
}
.f20{
font-size: 20rpx;
line-height: 20rpx;
}
</style>
效果图