638 lines
16 KiB
Vue
638 lines
16 KiB
Vue
<template>
|
||
<view>
|
||
<view v-if="showHeader" class="status" :style="{position:headerPosition,top:statusTop}"></view>
|
||
<view v-if="showHeader" class="header" :style="{position:headerPosition,top:headerTop}">
|
||
<view class="title">购物车</view>
|
||
</view>
|
||
<!-- 占位 -->
|
||
<view v-if="showHeader" class="place"></view>
|
||
<!-- 商品列表 -->
|
||
<view class="goods-list">
|
||
<view class="tis" v-if="goodsList.length==0">购物车是空的哦~</view>
|
||
<view class="row" v-for="(row,index) in goodsList" :key="index" >
|
||
<!-- 删除按钮 -->
|
||
<view class="menu" @tap.stop="deleteGoods(row.id)">
|
||
<view class="icon shanchu"></view>
|
||
</view>
|
||
<!-- 商品 -->
|
||
<view class="carrier" :class="[theIndex==index?'open':oldIndex==index?'close':'']" @touchstart="touchStart(index,$event)" @touchmove="touchMove(index,$event)" @touchend="touchEnd(index,$event)">
|
||
<view style=" width: 100%; padding: 20rpx 0 20rpx 150rpx;">
|
||
{{row.username}}
|
||
</view>
|
||
<view style="display: flex;width:100%">
|
||
<!-- checkbox -->
|
||
<view class="checkbox-box" @tap="selected(index)">
|
||
<view class="checkbox">
|
||
<view :class="[row.selected?'on':'']"></view>
|
||
</view>
|
||
</view>
|
||
<!-- 商品信息 -->
|
||
<view class="goods-info" @tap="toGoods(row)">
|
||
<view class="img">
|
||
<image :src="row.picurl"></image>
|
||
</view>
|
||
<view class="info">
|
||
<view class="title">{{row.title}}</view>
|
||
<!-- <view class="spec">{{row.spec}}</view> -->
|
||
<view class="price-number">
|
||
<view class="price">¥{{row._price}}</view>
|
||
<!-- <view style="display: flex;flex-shrink:0"> -->
|
||
<view class="number">
|
||
<view class="sub" @tap.stop="sub(index)">
|
||
<view class="icon jian"></view>
|
||
</view>
|
||
<view class="input" @tap.stop="discard">
|
||
<input type="number" v-model="row._num" @input="sum($event,index)" />
|
||
</view>
|
||
<view class="add" @tap.stop="add(index)">
|
||
<view class="icon jia"></view>
|
||
</view>
|
||
</view>
|
||
<icon type="cancel" size="26" @tap.stop="deleteGood(row.id, index)"/>
|
||
<!-- </view> -->
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 脚部菜单 -->
|
||
<view class="footer" :style="{bottom:footerbottom}">
|
||
<view class="checkbox-box" @tap="allSelect">
|
||
<view class="checkbox">
|
||
<view :class="[isAllselected?'on':'']"></view>
|
||
</view>
|
||
<view class="text">全选</view>
|
||
</view>
|
||
<!-- <view class="delBtn" @tap="deleteList" v-if="selectedList.length>0">删除</view> -->
|
||
<view class="settlement">
|
||
<view class="sum">总计(不含运费):<view class="money">¥{{sumPrice}}</view></view>
|
||
<view class="btn" @tap="toConfirmation">结算
|
||
<!-- ({{selectedList.length}}) -->
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
sumPrice:'0.00',
|
||
headerPosition:"fixed",
|
||
headerTop:null,
|
||
statusTop:null,
|
||
showHeader:true,
|
||
selectedList:[],
|
||
isAllselected:false,
|
||
goodsList:[
|
||
{id:1,img:'/static/img/goods/p1.jpg',name:'商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题',spec:'规格:S码',price:127.5,number:1,selected:false},
|
||
{id:2,img:'/static/img/goods/p2.jpg',name:'商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题',spec:'规格:S码',price:127.5,number:1,selected:false},
|
||
{id:3,img:'/static/img/goods/p3.jpg',name:'商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题',spec:'规格:S码',price:127.5,number:1,selected:false},
|
||
{id:4,img:'/static/img/goods/p4.jpg',name:'商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题',spec:'规格:S码',price:127.5,number:1,selected:false},
|
||
{id:5,img:'/static/img/goods/p5.jpg',name:'商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题商品标题',spec:'规格:S码',price:127.5,number:1,selected:false}
|
||
],
|
||
//控制滑动效果
|
||
theIndex:null,
|
||
oldIndex:null,
|
||
isStop:false
|
||
}
|
||
},
|
||
onPageScroll(e){
|
||
//兼容iOS端下拉时顶部漂移
|
||
this.headerPosition = e.scrollTop>=0?"fixed":"absolute";
|
||
this.headerTop = e.scrollTop>=0?null:0;
|
||
this.statusTop = e.scrollTop>=0?null:-this.statusHeight+'px';
|
||
},
|
||
//下拉刷新,需要自己在page.json文件中配置开启页面下拉刷新 "enablePullDownRefresh": true
|
||
onPullDownRefresh() {
|
||
this.getCart()
|
||
uni.stopPullDownRefresh()
|
||
},
|
||
onLoad() {
|
||
//兼容H5下结算条位置
|
||
// #ifdef H5
|
||
this.footerbottom = document.getElementsByTagName('uni-tabbar')[0].offsetHeight+'px';
|
||
// #endif
|
||
// #ifdef APP-PLUS
|
||
this.showHeader = false;
|
||
this.statusHeight = plus.navigator.getStatusbarHeight();
|
||
// #endif
|
||
|
||
},
|
||
onShow() {
|
||
this.getCart()
|
||
},
|
||
methods: {
|
||
getCart(){
|
||
this.$u.api.getCart().then(res=>{
|
||
var goodslist = []
|
||
for(var i=0;i<res.data.length;i++){
|
||
// for(var m=0;m<res.data[i].length;m++){
|
||
// res.data[i].shops[m].shopId = res.data[i].uid
|
||
// }
|
||
goodslist = goodslist.concat(res.data[i].shops)
|
||
}
|
||
this.goodsList = goodslist
|
||
this.selectedList=[]
|
||
this.isAllselected = false
|
||
this.sumPrice='0.00'
|
||
})
|
||
},
|
||
//加入商品 参数 goods:商品数据
|
||
joinGoods(goods){
|
||
/*
|
||
* 这里只是展示一种添加逻辑,模板并没有做从其他页面加入商品到购物车的具体动作,
|
||
* 在实际应用上,前端并不会直接插入记录到goodsList这一个动作,一般是更新列表和本地列表缓存。
|
||
* 一般商城购物车的增删改动作是由后端来完成的,
|
||
* 后端记录后返回前端更新前端缓存
|
||
*/
|
||
let len = this.goodsList.length;
|
||
let isFind = false;//是否找到ID一样的商品
|
||
for(let i=0;i<len;i++){
|
||
let row = this.goodsList[i];
|
||
if(row.id==goods.id )
|
||
{ //找到商品一样的商品
|
||
this.goodsList[i].number++;//数量自增
|
||
isFind = true;//找到一样的商品
|
||
break;//跳出循环
|
||
}
|
||
}
|
||
if(!isFind){
|
||
//没有找到一样的商品,新增一行到购物车商品列表头部
|
||
this.goodsList[i].unshift(goods);
|
||
}
|
||
},
|
||
//控制左滑删除效果-begin
|
||
touchStart(index,event){
|
||
//多点触控不触发
|
||
if(event.touches.length>1){
|
||
this.isStop = true;
|
||
return ;
|
||
}
|
||
this.oldIndex = this.theIndex;
|
||
this.theIndex = null;
|
||
//初始坐标
|
||
this.initXY = [event.touches[0].pageX,event.touches[0].pageY];
|
||
},
|
||
touchMove(index,event){
|
||
//多点触控不触发
|
||
if(event.touches.length>1){
|
||
this.isStop = true;
|
||
return ;
|
||
}
|
||
let moveX = event.touches[0].pageX - this.initXY[0];
|
||
let moveY = event.touches[0].pageY - this.initXY[1];
|
||
|
||
if(this.isStop||Math.abs(moveX)<5){
|
||
return ;
|
||
}
|
||
if (Math.abs(moveY) > Math.abs(moveX)){
|
||
// 竖向滑动-不触发左滑效果
|
||
this.isStop = true;
|
||
return;
|
||
}
|
||
|
||
if(moveX<0){
|
||
this.theIndex = index;
|
||
this.isStop = true;
|
||
}else if(moveX>0){
|
||
if(this.theIndex!=null&&this.oldIndex==this.theIndex){
|
||
this.oldIndex = index;
|
||
this.theIndex = null;
|
||
this.isStop = true;
|
||
setTimeout(()=>{
|
||
this.oldIndex = null;
|
||
},150)
|
||
}
|
||
}
|
||
},
|
||
touchEnd(index,$event){
|
||
//结束禁止触发效果
|
||
this.isStop = false;
|
||
},
|
||
//控制左滑删除效果-end
|
||
|
||
|
||
//商品跳转
|
||
toGoods(e){
|
||
uni.showToast({title: '商品'+e.id,icon:"none"});
|
||
uni.navigateTo({
|
||
url: '../../goods/goods?id='+e.id
|
||
});
|
||
},
|
||
//跳转确认订单页面
|
||
toConfirmation(){
|
||
let tmpList=[];
|
||
let len = this.goodsList.length;
|
||
for(let i=0;i<len;i++){
|
||
if(this.goodsList[i].selected) {
|
||
let good = {
|
||
id: this.goodsList[i].id,
|
||
picurl: this.goodsList[i].picurl,
|
||
title: this.goodsList[i].title,
|
||
// spec: '规格:' + this.goodsData.spec[this.selectSpec],
|
||
price: this.goodsList[i].price,
|
||
_num: this.goodsList[i]._num,
|
||
shopId: this.goodsList[i].uid
|
||
};
|
||
tmpList.push(good);
|
||
}
|
||
}
|
||
if(tmpList.length<1){
|
||
uni.showToast({
|
||
title:'请选择商品结算',
|
||
icon:'none'
|
||
});
|
||
return ;
|
||
}
|
||
uni.setStorage({
|
||
key:'buylist',
|
||
data:tmpList,
|
||
success: () => {
|
||
uni.navigateTo({
|
||
url:'../../order/confirmation'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
//删除商品
|
||
deleteGoods(id){
|
||
let len = this.goodsList.length;
|
||
this.$u.api.removeFromCart(id).then(res=>{
|
||
for(let i=0;i<len;i++){
|
||
if(id==this.goodsList[i].id){
|
||
this.goodsList.splice(i, 1);
|
||
break;
|
||
}
|
||
}
|
||
this.selectedList.splice(this.selectedList.indexOf(id), 1);
|
||
this.sum();
|
||
this.oldIndex = null;
|
||
this.theIndex = null;
|
||
}).catch(e=>{
|
||
uni.showToast({
|
||
title:'移除失败'
|
||
})
|
||
})
|
||
|
||
},
|
||
//移除一件商品
|
||
deleteGood(id, index){
|
||
var that = this
|
||
that.$u.api.removeFromCart(id).then(res=>{
|
||
|
||
that.goodsList.splice(index, 1)
|
||
this.sum()
|
||
})
|
||
},
|
||
// 删除商品s
|
||
deleteList(){
|
||
let len = this.selectedList.length;
|
||
while (this.selectedList.length>0)
|
||
{
|
||
this.deleteGoods(this.selectedList[0]);
|
||
}
|
||
this.selectedList = [];
|
||
this.isAllselected = this.selectedList.length == this.goodsList.length && this.goodsList.length>0;
|
||
this.sum();
|
||
},
|
||
// 选中商品
|
||
selected(index){
|
||
this.goodsList[index].selected = this.goodsList[index].selected?false:true;
|
||
let i = this.selectedList.indexOf(this.goodsList[index].id);
|
||
i>-1?this.selectedList.splice(i, 1):this.selectedList.push(this.goodsList[index].id);
|
||
this.isAllselected = this.selectedList.length == this.goodsList.length;
|
||
this.sum();
|
||
},
|
||
//全选
|
||
allSelect(){
|
||
let len = this.goodsList.length;
|
||
let arr = [];
|
||
for(let i=0;i<len;i++){
|
||
this.goodsList[i].selected = this.isAllselected? false : true;
|
||
arr.push(this.goodsList[i].id);
|
||
}
|
||
this.selectedList = this.isAllselected?[]:arr;
|
||
this.isAllselected = this.isAllselected||this.goodsList.length==0?false : true;
|
||
this.sum();
|
||
},
|
||
// 减少数量
|
||
sub(index){
|
||
if(this.goodsList[index]._num<=1){
|
||
return;
|
||
}
|
||
this.goodsList[index]._num--;
|
||
this.sum();
|
||
},
|
||
// 增加数量
|
||
add(index){
|
||
this.goodsList[index]._num++;
|
||
this.sum();
|
||
},
|
||
// 合计
|
||
sum(e,index){
|
||
this.sumPrice=0;
|
||
let len = this.goodsList.length;
|
||
for(let i=0;i<len;i++){
|
||
if(this.goodsList[i].selected) {
|
||
if(e && i==index){
|
||
this.sumPrice = this.sumPrice + (e.detail.value*this.goodsList[i]._price);
|
||
}else{
|
||
this.sumPrice = this.sumPrice + (this.goodsList[i]._num*this.goodsList[i]._price);
|
||
}
|
||
}
|
||
}
|
||
this.sumPrice = this.sumPrice.toFixed(2);
|
||
},
|
||
discard() {
|
||
//丢弃
|
||
}
|
||
|
||
|
||
}
|
||
}
|
||
</script>
|
||
<style lang="scss">
|
||
page{position: relative;background-color: #fff;}
|
||
.checkbox-box{
|
||
display: flex;
|
||
align-items: center;
|
||
.checkbox{
|
||
width: 35upx;
|
||
height: 35upx;
|
||
border-radius: 100%;
|
||
border: solid 2upx #f06c7a;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
.on{
|
||
width: 25upx;
|
||
height: 25upx;
|
||
border-radius: 100%;
|
||
background-color: #f06c7a;
|
||
}
|
||
}
|
||
.text{
|
||
font-size: 28upx;
|
||
margin-left: 10upx;
|
||
}
|
||
}
|
||
.status {
|
||
width: 100%;
|
||
height: 0;
|
||
position: fixed;
|
||
z-index: 10;
|
||
background-color: #fff;
|
||
top: 0;
|
||
/* #ifdef APP-PLUS */
|
||
height: var(--status-bar-height);//覆盖样式
|
||
/* #endif */
|
||
}
|
||
|
||
.header{
|
||
width: 92%;
|
||
padding: 0 4%;
|
||
height: 100upx;
|
||
display: flex;
|
||
align-items: center;
|
||
position: fixed;
|
||
top: 0;
|
||
z-index: 10;
|
||
background-color: #fff;
|
||
/* #ifdef APP-PLUS */
|
||
top: var(--status-bar-height);
|
||
/* #endif */
|
||
.title{
|
||
font-size: 36upx;
|
||
}
|
||
|
||
}
|
||
.place{
|
||
|
||
background-color: #ffffff;
|
||
height: 100upx;
|
||
/* #ifdef APP-PLUS */
|
||
margin-top: var(--status-bar-height);
|
||
/* #endif */
|
||
}
|
||
.goods-list{
|
||
width: 100%;
|
||
padding: 20upx 0 120upx 0;
|
||
.tis{
|
||
width: 100%;
|
||
height: 60upx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-size: 32upx;
|
||
}
|
||
.row{
|
||
width: calc(92%);
|
||
height: calc(22vw + 110upx);
|
||
margin: 20upx auto;
|
||
|
||
border-radius: 15upx;
|
||
box-shadow: 0upx 5upx 20upx rgba(0,0,0,0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
position: relative;
|
||
overflow: hidden;
|
||
z-index: 4;
|
||
border: 0;
|
||
.menu{
|
||
.icon{
|
||
color: #fff;
|
||
// font-size: 25upx;
|
||
}
|
||
position: absolute;
|
||
width: 30%;
|
||
height: 100%;
|
||
right: 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background-color: red;
|
||
color: #fff;
|
||
z-index: 2;
|
||
}
|
||
.carrier{
|
||
flex-direction: column;
|
||
@keyframes showMenu {
|
||
0% {transform: translateX(0);}100% {transform: translateX(-30%);}
|
||
}
|
||
@keyframes closeMenu {
|
||
0% {transform: translateX(-30%);}100% {transform: translateX(0);}
|
||
}
|
||
&.open{
|
||
animation: showMenu 0.25s linear both;
|
||
}
|
||
&.close{
|
||
animation: closeMenu 0.15s linear both;
|
||
}
|
||
background-color: #fff;
|
||
.checkbox-box{
|
||
padding-left: 20upx;
|
||
flex-shrink: 0;
|
||
height: 22vw;
|
||
margin-right: 20upx;
|
||
}
|
||
position: absolute;
|
||
width: 100%;
|
||
padding: 0 0;
|
||
height: 100%;
|
||
z-index: 3;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.goods-info{
|
||
width: 100%;
|
||
display: flex;
|
||
padding-right: 20upx;
|
||
.img{
|
||
width: 22vw;
|
||
height: 22vw;
|
||
border-radius: 10upx;
|
||
overflow: hidden;
|
||
flex-shrink: 0;
|
||
margin-right: 10upx;
|
||
image{
|
||
width: 22vw;
|
||
height: 22vw;
|
||
}
|
||
}
|
||
.info{
|
||
width: 100%;
|
||
height: 22vw;
|
||
overflow: hidden;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
position: relative;
|
||
.title{
|
||
width: 100%;
|
||
font-size: 28upx;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
// text-align: justify;
|
||
overflow: hidden;
|
||
}
|
||
.spec{
|
||
font-size: 20upx;
|
||
background-color: #f3f3f3;
|
||
color: #a7a7a7;
|
||
height: 30upx;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 10upx;
|
||
border-radius: 15upx;
|
||
margin-bottom: 20vw;
|
||
}
|
||
.price-number{
|
||
position: absolute;
|
||
width: 100%;
|
||
bottom: 0upx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-end;
|
||
font-size: 28upx;
|
||
height: 60upx;
|
||
.price{
|
||
}
|
||
.number{
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: flex-end;
|
||
margin-right: 10upx;
|
||
.input{
|
||
width: 60upx;
|
||
height: 60upx;
|
||
margin: 0 10upx;
|
||
background-color: #f3f3f3;
|
||
input{
|
||
width: 60upx;
|
||
height: 60upx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
text-align: center;
|
||
font-size: 26upx;
|
||
}
|
||
}
|
||
.sub ,.add{
|
||
width: 45upx;
|
||
height: 45upx;
|
||
background-color: #f3f3f3;
|
||
border-radius: 5upx;
|
||
.icon{
|
||
font-size: 22upx;
|
||
width: 45upx;
|
||
height: 45upx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.footer{
|
||
width: 92%;
|
||
padding: 0 4%;
|
||
background-color: #fbfbfb;
|
||
height: 100upx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 28upx;
|
||
position: fixed;
|
||
bottom: 0upx;
|
||
z-index: 5;
|
||
.delBtn{
|
||
border: solid 1upx #f06c7a;
|
||
color: #f06c7a;
|
||
padding: 0 30upx;
|
||
height: 50upx;
|
||
border-radius: 30upx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
.settlement{
|
||
width: 75%;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
.sum{
|
||
width: 75%;
|
||
font-size: 28upx;
|
||
margin-right: 10upx;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
.money{
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
.btn{
|
||
padding: 0 30upx;
|
||
height: 50upx;
|
||
background-color: #f06c7a;
|
||
color: #fff;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
border-radius: 30upx;
|
||
}
|
||
}
|
||
}
|
||
</style>
|