九 pages/index/index.vue

82 阅读1分钟
<template>
	<view class="content">
		<swiper 
			vertical
			circular
			:style="{ height : height + 'px'}"
			:current='swiperActiveIndex'
			@change='swiperChange'
		>
			<swiper-item 
				:style="{ height : height + 'px'}"
				v-for='item in swiperList'
				:key='item.id'
				@click.stop='details(item.id)'
			>
				<view class='goods' @click.stop='show=true'>
					<view class='goods-cart'>
						<image src='../../static/images/shop.png'></image>
					</view>
					<view class='goods-title'>
						<view>{{ item.title }}</view>
					</view>
				</view>
				<image :src='item.skus[0].resources[0].resPath' :style="{ height : height + 'px'}"></image>
			</swiper-item>
		</swiper>
		
		<!--立即购买 弹出层-->
		<u-popup :show="show" @close="show=false" @open="show=true">
			<view>
				<image :src='goods.img'></image>
				<view>
					<view>{{ changePrice(goods.price) }}</view>
					<view>{{ goods.title }}</view>
					<view>
						<button open-type="share" class='share'>分享</button>
						<view 
							@click.stop='$u.debounce(fav, 1000)'
							:class='goods.isFav==1?"fav-active":""'
						>收藏 {{ goods.isFav }}</view>
						<button @click.stop='goPayment'>立即购买</button>
					</view>
				</view>
			</view>
		</u-popup>
		
		<!--选择商品规格-->
		<u-popup :show="isShow" @close="isShow=false" @open="isShow=true">
			<view class='goods-main'>
				<view class='goods-img'>
					<image :src="goodsCurrent.resources[0].resPath" mode=""></image>
					<view> {{ goodsCurrent.currentPrice }} </view>
				</view>
				<view v-for='item in spec' :key='item.id' class='goods-sku'>
					<view>{{ item.name}} ({{ item.children.length }})</view>
					<view class='sku-item'>
						<view 
							v-for='(k,index) in item.children' 
							:key='index'
							@click.stop='skuBtn(item,k.name)'
							:class='k.active?"skus-active":""'
						>
							{{ k.name }}
						</view>
					</view>
				</view>
				<view v-if='goodsCurrent.stock == 0'>
					商品已售罄....
				</view>
				<view v-else class='goods-number'>
					<view>购买数量</view>
					<u-number-box :min="1" :max="goodsCurrent.stock" v-model="number"></u-number-box>
				</view>
				<view class='goods-order'>
					<button 
						:disabled="goodsCurrent.stock == 0"
						@click='confirmOrder'
					>立即购买</button>
				</view>
			</view>
		</u-popup>
		<u-toast ref="uToast"></u-toast>
	</view>
</template>

<script>
import { goodsPage , getGoods } from '@/utils/api/goods.js'
import changeGoods from '@/mixins/changeGoods.js'
import { collectAdd , collectDelete  } from '@/utils/api/fav.js'
export default {
	mixins:[changeGoods],
	data() {
		return {
			height:'',//可视区域高度
			swiperActiveIndex:0,//swiper当前所在滑块的index
			goodsList:[],//请求所有商品数据
			swiperList:[],//最终展示商品数据
			pages:{		 //请求数据的参数
				current:1,
				size:10
			},
			currentIndex:0, //当前展示商品的索引
			show:false, //立即购买弹出层控制 
			isShow:false,//展示商品规格弹出层控制
			goods:{		//当前商品的详情
				id:0,
				img:'',
				title:'',
				price:0,
				isFav:0,
			},
			spec:[],   //商品规格数据
			skus:[],   //自定义规格数据
			goodsCurrent:[], //当前规格数据
			number:1,//商品下单数量
		}
	},
	onLoad() { 
		//获取初始化数据
		this.dataInit();
		//获取可视区域高度
		this.height = uni.getSystemInfoSync().windowHeight;
	},
	methods: {
		//获取所有数据
		async dataInit(){
			let { current , size  } = this.pages;
			let res = await goodsPage({ current , size });
			this.goodsList = Object.freeze( [...this.goodsList , ...this.convert(res.data.records)] );
			//获取截取后的数据
			this.getShowList();
		},
		//把某些字段转换成对象
		convert( record ){
			record.forEach(item=>{
				(item.skus).forEach( skusItem=>{
					skusItem.resources = JSON.parse( skusItem.resources );
				})
			})
			return record;
		},
		//截取数据
		getShowList(){
			//起始位置==>数据
			let currentValue = this.goodsList[this.currentIndex];
			//中间位置==>数据
			let nextValue = this.goodsList[ this.getDataIndex( this.currentIndex + 1 ) ]; 
			//结尾数据==>数据
			let prevValue = this.goodsList[ this.getDataIndex( this.currentIndex - 1 ) ]
			
			//给swiper数组填充数据
			this.swiperList = new Array(3);
			
			// 滑动到第current下标 = 第currentIndex个元素
			this.swiperList[ this.swiperActiveIndex ] = currentValue;
			// 滑动到第current+1下标 = 第currentIndex + 1个元素
			this.swiperList[ this.getSwiperIndex( this.swiperActiveIndex + 1 ) ] = nextValue;
			// 滑动到第swiperList.length-1下标 = 第 goodsList - 1 个元素
			this.swiperList[ this.getSwiperIndex( this.swiperActiveIndex - 1 ) ] = prevValue;
			
			//当前swiper展示的商品
			let goods = this.swiperList[this.swiperActiveIndex];
			
			this.goods = {
				id:goods.id,
				img:goods.skus[0].resources[0].resPath,
				title:goods.title,
				price:goods.skus[0].currentPrice,
				isFav:goods.isCollected
			}
		},
		getDataIndex( index ){
			if( index < 0 ){
				return this.goodsList.length - 1;
			}else if( index >= this.goodsList.length ){
				return 0;
			}else{
				return index;
			}
		},
		getSwiperIndex( index ){
			if( index < 0 ){
				return this.swiperList.length - 1;
			}else if( index >= this.swiperList.length ){
				return 0;
			}else{
				return index;
			}
		},
		//swiper的 current 改变时会触发
		swiperChange( e ){
			//当前swiper-item的索引 ===> 0 , 1 , 2 
			let current = e.detail.current;
		
			if( [1,1-this.swiperList.length].includes(current-this.swiperActiveIndex) ){
				//指针向下滑动
				this.currentIndex = this.getDataIndex( this.currentIndex + 1 );
			}else{//指针向上滑动
				this.currentIndex = this.getDataIndex( this.currentIndex - 1 );
				//有问题 ===》 判断是否要加载数据
				if( this.currentIndex == this.goodsList.length-1 ){
					//加载下一页数据
					this.pages.current++;
					this.dataInit();
				}
			}
			//给swiperActiveIndex【滑块的位置是下标几?】
			this.swiperActiveIndex = current;
			this.getShowList(); 
		},
		//立即购买展示规格
		async goPayment(){
			//关闭当前弹窗
			this.show = false;
			//当前商品的id拿到
			let { id } = this.goods;
			//当前商品详情
			let res = await getGoods(id);
			//数据
			let data = res.data;
			//规格标题
			let specialSpecArray = data.specialSpecArray;
			//规格详情
			let specialSpec = JSON.parse( data.specialSpec );
			//重构后的规格数据
			let spec = [];
			//自定义sku数据
			let skus = data.skus;
			//重构skus
			for( let i=0;i<skus.length;i++){
				skus[i].resources = JSON.parse(  skus[i].resources );
				skus[i].specialSku = JSON.parse(  skus[i].specialSku );
				
				for( let k in skus[i].specialSku ){
					skus[i][k] = skus[i].specialSku[k];
				}
			}
			this.skus = skus;
			//默认规格数据
			this.goodsCurrent = skus[0];
			
			//重构规格数据
			specialSpecArray.forEach(v=>{
				//每一项对象中新建children字段
				let children = [];
				for( let i=0;i<specialSpec[v.id].length;i++){
					children.push({
						name:specialSpec[v.id][i],
						active:specialSpec[v.id][i] == this.goodsCurrent[v.id] ? true : false 
					})
				}
				spec.push({
					id:v.id,
					name:v.name,
					children
				})
			})
			//赋值多规格数据
			this.spec = spec;
			//展示弹出层
			this.isShow = true;
		},
		//点击规格
		skuBtn( item , name ){
			//当前选中的规格的数据
			let currentObj = {};
			//点击某一行,添加的样式
			for( let i=0;i<this.spec.length; i++){
				if( this.spec[i]['id'] == item.id ){
					this.spec[i].children.forEach(v=>{
						//所有的为false
						v.active = false;
						if( v.name == name ){
							//当前为true
							v.active = true;
						}
					})
				}
				
				this.spec[i].children.forEach(v=>{
					if( v.active ){
						currentObj[this.spec[i].id] = v.name;
					}
				})
			}
			
			for( let i=0;i<this.skus.length;i++){
				//当前选中的数据和skus总数据的某一条数据的规格,相等的次数
				let number = 0;
				for(let k in currentObj){
					if( this.skus[i][k] == currentObj[k] ){
						number++;
					}
				}
				
				if(  number ==  Object.keys(currentObj).length  ){
					this.goodsCurrent = this.skus[i]; 
				}
			}
		},
		//进入商品详情
		details( id ){
			uni.navigateTo({
				url:`/pages/goods-detail?id=${id}`
			})
		},
		//进入确认订单页
		confirmOrder(){
		
			//用户是不是登录状态
			if( !this.$store.state.userInfo.status ){
				return uni.navigateTo({
					url:'/login/login'
				})
			}
			//解构
			let { id , currentPrice , stock , spuId } = this.goodsCurrent;
			let { img , title  } = this.goods;
			
			//参数
			let confirm = {
				id,
				currentPrice, 
				stock, 
				img,
				title, 
				spuId, 
				number:this.number
			}
			//进入确认订单页
			uni.navigateTo({
				url:`/order/confirmOrder?goods=${ JSON.stringify(confirm) }`
			})
		},
		//收藏
		async fav(){
			let { id } = this.goods;
			
			//添加收藏
			if( this.goods.isFav == 0 ){
				console.log('添加收藏');
				let res = await collectAdd(id);
				if( res.code !='200' ) return;
				this.$refs.uToast.show({
					type:"success",
					message:"收藏成功"
				})
				this.goods.isFav = 1;
				return ;
			}
			
			//删除收藏
			if( this.goods.isFav == 1 ){
				console.log( '删除收藏' )
				let res = await collectDelete(id);
				if( res.code !='200' ) return;
				this.$refs.uToast.show({
					type:"success",
					message:"取消收藏"
				})
				this.goods.isFav = 0;
				return ;
			}
		}
	}
}
</script>

<style>
.content image{
	width:100%;
}
.goods{
	display: flex;
	position: absolute;
	bottom:64rpx;
	left:50%;
	z-index: 666;
	transform: translateX(-50%);
}
.goods-cart{
	display: flex;
	align-items: center;
	justify-content: center;
	width: 94rpx;
	height: 94rpx;
	background: rgba(0,0,0,.7);
	border-radius: 50%;
}
.goods-cart image{
	width: 43rpx;
	height: 35rpx;
}
.goods-title{
	display: flex;
	align-items: center;
	justify-content: center;
	width: 562rpx;
	margin-left: 9rpx;
	background: rgba(0,0,0,.7);
	border-radius: 36px;
	color:#fff;
}
.goods-title view{
	padding: 0 20rpx;
	font-size:24rpx;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}
.goods-main{
	padding:17rpx;
}
.goods-img{
	display: flex;
	align-items: center;
}
.goods-img image{
	width: 115rpx;
	height: 116rpx;
	background: #FFFFFF;
	border-radius: 7rpx;
	border: 1px solid #707070;
}
.goods-img view{
	margin-left:19rpx;
}
.goods-sku{
	margin:16rpx 0;
}
.sku-item{
	display: flex;
}
.sku-item > view{
	padding:10rpx 20rpx;
	background: #F7F7F7;
	border-radius: 7px;
	color:#000;
}
.sku-item view + view{
	margin-left:30rpx;
}
.goods-number{
	display: flex;
	justify-content: space-between;
	margin-top: 100rpx;
}
.goods-order{
	display: flex;
	align-items: center;
	justify-content: center;
	margin-top: 300rpx;
}
.goods-order button{
	width: 490rpx;
	height: 85rpx;
	background: linear-gradient(128deg, #525252 0%, #000000 100%);
	border-radius: 43rpx;
	color:#fff;
}
.skus-active{
	border:1px solid blue;
}
.share{
	border: none!important;
	border-radius: 0!important;
	background-color: #f8f8f8;
	color: #000;
	display: inline-block;
	margin-left: auto;
	margin-right: auto;
	padding:0rpx;
}
.fav-active{
	color:red;
}
</style>