Vue电商平台项目(5)

分类页布局

src/views/List.vue文件代码

<template>
	<div class='list'>
		<header>
			<div class='returns'>
				<i class='iconfont icon-fanhui'></i>
			</div>
			<div class='search'>
				<i class='iconfont icon-fangdajing'></i>
				<span>搜您喜欢的...</span>
			</div>
			<div class='go-home'>
				<img src="@/assets/images/home.png" alt="">
			</div>
		</header>
		<section>
			<div class='list-l'>
				<ul class='l-item'>
					<li class='active'>推荐</li>
					<li>推荐</li>
					<li>推荐</li>
					<li>推荐</li>
					<li>推荐</li>
				</ul>
			</div>
			
			<div class='list-r'>
				<ul>
					<li class='shop-list'>
						<h2>推荐</h2>
						<ul class='r-content'>
							<li>
								<img src="@/assets/images/list1.jpeg" alt="">
								<span>铁观音</span>
							</li>
							<li>
								<img src="@/assets/images/list1.jpeg" alt="">
								<span>铁观音</span>
							</li>
							<li>
								<img src="@/assets/images/list1.jpeg" alt="">
								<span>铁观音</span>
							</li>
							<li>
								<img src="@/assets/images/list1.jpeg" alt="">
								<span>铁观音</span>
							</li>
							<li>
								<img src="@/assets/images/list1.jpeg" alt="">
								<span>铁观音</span>
							</li>
						</ul>
					</li>
				</ul>
			</div>
			
		</section>
		<Tabbar></Tabbar> 
	</div>
</template>

<script>
import Tabbar from '@/components/common/Tabbar.vue'
export default {
  name: "List",
  components:{
  	Tabbar
  }
};
</script>
<style scoped lang='scss'>
.list{
	display: flex;
	flex-direction: column;
	width: 100vw;
	height: 100vh;
	overflow: hidden;
}
header{
	display: flex;
	justify-content: space-between;
	align-items: center;
	height: 1.173333rem;
	background-color: #b0352f;
	.returns{
		line-height: 1.173333rem;
		padding:0 0.533333rem;
		i{
			color:#fff;
			font-size:0.693333rem;
		}
	}
	.search{
		display: flex;
		align-items: center;
		flex: 1;
		padding:0.16rem 0.266666rem;
		background-color: #FFFFFF;
		border-radius: 0.64rem;
		i{
			padding-right: 0.16rem;
			color:#666;
			font-size:0.48rem;
		}
		span{
			color:#666;
			font-size:0.373333rem;
		}
	}
	.go-home{
		padding: 0 0.266666rem;
		line-height: 1.173333rem;
		img{
			width: 0.48rem;
			height: 0.48rem;
		}
	}
}
section{
	display: flex;
	flex:1;
	overflow:hidden;
}
.list-l{
	width: 2.48rem;
	background-color: #fff;
	border-right: 1px solid #CCCCCC;
	overflow: hidden;
	.l-item{
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		li{
			width: 100%;
			line-height: 1.333333rem;
			text-align: center;
			font-size:0.373333rem;
			&.active{
				color:#b54f4a;
				border-left:6px solid #b54f4a;
			}
		}
	}
}

.list-r{
	flex:1;
	overflow: hidden;
	.shop-list{
		text-align: center;
		h2{
			padding:0.533333rem 0;
			font-size:0.64rem;
			font-weight: 400;
		}
		.r-content{
			display: flex;
			flex-wrap: wrap;
			li{
				display: flex;
				flex-direction: column;
				justify-content: center;
				align-items: center;
				width: 33.33%;
				padding:0.266666rem 0;
				img{
					width: 1.413333rem;
					height: 1.413333rem;
				}
				span{
					font-size:0.426666rem;
				}
			}
		}
	}
}
::v-deep.tabbar{
	border-top:1px solid #CCCCCC;
}
</style>

分类页数据渲染

  1. server/routes/index.js文件进行接口配置
router.get('/api/goods/list',function(req,res,next){
	res.send({
		code:0,
		data:[
		       {
		       }
		]
	})
})	
  1. src/views/List.vue引入接口,渲染数据
		<section>
			<div class='list-l'>
				<ul class='l-item'>
					<li 
					v-for='(item,index) in leftData'
					:key='index'
					class='active'>{{item.name}}</li>
				</ul>
			</div>
			
			<div class='list-r'>
				<ul
				   v-for='(item,index) in rightData'
				   :key='index'
				   class='shop-list'
				>
					<li 
					    v-for="(k,i) in item"
					    :key='i'
					>
						<h2>{{k.name}}</h2>
						<ul class='r-content'>
							<li v-for='(j,idx) in k.list'
								:key='idx'>
								<img :src="j.imgUrl" alt="">
								<span>{{j.name}}</span>
							</li>
						</ul>
					</li>
				</ul>
			</div>
			
		</section>
import http from '@/common/api/request.js'
export default {
  name: "List",
  data () {
	  return {
		leftData:[],//左侧数据
		rightData:[]//右侧数据
	  }
  },
  components:{
  	Tabbar
  },
  async created(){
	  
	let res = await http.$axios({
		url:'/api/goods/list',
	})
	
	let leftArr = [];
	let rightArr = [];
	
	res.forEach(v=>{
		leftArr.push({
			id:v.id,
			name:v.name
		})
		rightArr.push( v.data );
	})
	this.leftData = leftArr;
	this.rightData = rightArr;
  }
};
</script>

效果图:
在这里插入图片描述

实现商品分类左右联动

<section>
		<div class='list-l' ref='left'>
			<ul class='l-item'>
				<li 
					v-for='(item,index) in leftData'
					:key='index'
					:class='{active:index==currentIndex}'
			        @click='goScroll(index)'
					>{{item.name}}</li>
			</ul>
		</div>
		<div class='list-r' ref='right'>
			<div>
				<ul
				  v-for='(item,index) in rightData'
				   :key='index'
				   class='shop-list'
				>
					<li 
					   v-for="(k,i) in item"
					   :key='i'
						>
						<h2>{{k.name}}</h2>
						<ul class='r-content'>
							<li v-for='(j,idx) in k.list'
								:key='idx'>
								<img :src="j.imgUrl" alt="">
								<span>{{j.name}}</span>
							</li>
						</ul>
					</li>
				</ul>
			</div>
		</div>
  </section>
<script>
import BetterScroll from 'better-scroll'
import Tabbar from '@/components/common/Tabbar.vue'
import http from '@/common/api/request.js'
export default {
  name: "List",
  data () {
	  return {
		leftData:[],//左侧数据
		rightData:[],//右侧数据
		rightBScroll:'',//右侧滑动BScroll
		allHeight:[],//承载右侧每一块的高度值
		scrollY:''//右侧滚动距离
	  }
  },
  computed:{
  		currentIndex(){
  			return this.allHeight.findIndex((item, index)=>{
  				return this.scrollY >= item-100 && this.scrollY < this.allHeight[index+1]-100
  			})
  		}
  },
  components:{
  	Tabbar
  },
  async created(){
	  
	let res = await http.$axios({
		url:'/api/goods/list',
	})
	
	let leftArr = [];
	let rightArr = [];
	
	res.forEach(v=>{
		leftArr.push({
			id:v.id,
			name:v.name
		})
		rightArr.push( v.data );
	})
	this.leftData = leftArr;
	this.rightData = rightArr;
	
	this.$nextTick(()=>{
		//左侧滑动
		new BetterScroll(this.$refs.left,{
			click:true
		});
		//右侧滑动
		this.rightBScroll = new BetterScroll(this.$refs.right,{
			click:true,
			probeType:3
		});
		//统计右侧所有板块高度值,并且放入数组中
		let height = 0;
		this.allHeight.push(height);
		//获取右侧每一块高度
		let uls = this.$refs.right.getElementsByClassName('shop-list');
		//把dom对象转换成功真正的数组
		Array.from(uls).forEach(v=>{
			height += v.clientHeight
			this.allHeight.push( height )
		})
		//得到右侧滚动的值
		this.rightBScroll.on('scroll',(pos)=>{
			this.scrollY = Math.abs( pos.y );
		})
		
	})
  },
  methods:{
  	  goScroll( index ){
  		this.rightBScroll.scrollTo(0,-this.allHeight[index],300);
  	  }
  }
};
</script>

进入商品详情页

  1. 新建src/views/Detail.vue,进行页面布局,并在src/router/index.js进行配置
  2. server/routes/index.js文件进行接口配置,src/views/Detail.vue中引入接口
//查询商品id的数据接口
router.get('/api/goods/id',function(req,res,next){
	let id = req.query.id;
	connection.query('select * from goods_list where id='+id+'',function(error,results){
		if( error ) throw error;
		res.json({
			code:0,
			data:results[0]
		})
	})
});

Detail.vue整体代码如下:

<template>
	<div class='detail'>
		<header>
			<div class='header-returns' v-show='isShow'>
				<div @click='goBack'>
					<i class='iconfont icon-fanhui'></i>
				</div>
				<div>
					<i class='iconfont icon-kefu'></i>
				</div>
			</div>
			
			<div 
				class='header-bar' 
				v-show='!isShow'
				:style='styleOption'
			>
				<div @click='goBack'>
					<i class='iconfont icon-fanhui'></i>
				</div>
				<div>
					<span>商品详情</span>
					<span>商品评价</span>
				</div>
				<div>
					<i class='iconfont icon-kefu'></i>
				</div>
			</div>
		</header>
		<section ref='wrapper'>
			<div>
				<div class='swiper-main'>
					<swiper :options="swiperOption">
					  <swiper-slide 
						v-for='(item,index) in swiperList' 
						:key='index'
					   >
						<img :src="item.imgUrl" alt="">
					  </swiper-slide>
					</swiper>
					<div class="swiper-pagination"></div> 
				</div>
				<div class='goods-name'>
					<h1>{{goods.name}}</h1>
					<div>性价首选,茶感十足、鲜醇耐泡的大众口粮茶</div>
				</div>
				<div class='goods-price'>
					<div class='oprice'>
						<span>¥</span>
						<b>{{goods.price}}</b>
					</div>
					<div class='pprice'>
						<span>价格:</span>
						<del>¥{{goods.price}}</del>
					</div>
				</div>
				<div>
					<img style='width:100%;height: 500px;' :src="goods.imgUrl" alt="">
					<img style='width:100%;height: 500px;' :src="goods.imgUrl" alt="">
				</div>
			</div>
		</section>
		<footer>
			<div class='add-cart' @click='addCart'>加入购物车</div>
			<div >立即购买</div>
		</footer>
	</div>
</template>

<script>
import 'swiper/dist/css/swiper.css'
import { swiper, swiperSlide } from 'vue-awesome-swiper'
import BetterScroll from 'better-scroll'
import http from '@/common/api/request.js'
import { Toast } from 'mint-ui';
export default{
	data(){
	  return{
			id:0,
			goods:{},
			styleOption:{},
			BetterScroll:'',
		    isShow:true,
			swiperOption: {
				autoplay: 3000,
				speed: 1000,
				pagination: {
					el: '.swiper-pagination',
					type:'fraction'
				}
			},
			swiperList:[
				{
					imgUrl:'./images/goods1.jpg'
				},
				{
					imgUrl:'./images/goods2.jpg'
				},
				{
					imgUrl:'./images/goods3.jpg'
				}
			]
	  }
	},
	components: {
	  swiper,
	  swiperSlide
	},
	created(){
		
		this.id = this.$route.query.id;
		
		this.getData();
	},
	mounted(){
		this.BetterScroll = new BetterScroll(this.$refs.wrapper, {
			probeType: 3,
			bounce: false,
			click:true
		})
		this.BetterScroll.on('scroll',(pos)=>{
			let posY = Math.abs( pos.y );
			let opacity = posY / 180;
			
			opacity = opacity > 1 ? 1 : opacity;
			
			this.styleOption = {
				opacity:opacity
			}
				
			if( posY >= 70 ){
				this.isShow = false;
			}else{
				this.isShow = true;
			}
		})
	},
	activated(){
		
		//判断当前url , id和之前id是否一致
		if(  this.$route.query.id != this.id ){
			this.getData();
			this.id = this.$route.query.id;
		}
		
	},
	methods:{
		async getData(){
			let id = this.$route.query.id;
			let res = await http.$axios({
				url:'/api/goods/id',
				params:{
					id
				}
			})
			this.goods = res;
		},
        //加入购物车
        addCart(){
            let id = this.$route.query.id;
            http.$axios({
                url:'/api/addCart',
                method:"post",
                data:{
                    goodsId:id
                },
                headers:{
                    token:true
                }
            }).then(res=>{
                if( res.success ){
                    Toast('添加购物车成功');
                }
            })
        },
		//返回上一页
		goBack(){
			this.$router.back();
		}
	}
}
</script>

<style scoped lang="scss">
.detail{
	display: flex;
	flex-direction: column;
	width: 100vw;
	height: 100vh;
	overflow: hidden;
}
header{
	position:fixed;
	left:0;
	top:0;
	z-index: 999;
	width: 100%;
	height: 1.173333rem;
	.header-returns{
		display: flex;
		justify-content: space-between;
		align-items: center;
		width: 100%;
		height: 1.173333rem;
		div{
			margin:0 0.266666rem;
			width: 0.933333rem;
			line-height: 0.906666rem;
			text-align: center;
			background-color: rgba(0,0,0,0.3);
			border-radius: 50%;
		}
		i{
			font-size:0.693333rem;
			color:#fff;
		}
	}
	.header-bar{
		display: flex;
		justify-content: space-between;
		align-items: center;
		width: 100%;
		height: 1.173333rem;
		font-size:0.426666rem;
		background-color: #fff;
		span{
			padding:0 0.266666rem;
		}
		i{
			padding:0 0.266666rem;
			font-size:0.586666rem;
		}
	}
}
section{
	flex:1;
	overflow: hidden;
}
.swiper-main{
	position: relative;
	width: 100%;
	height:10rem;
	overflow: hidden;
}
.swiper-container{
	width: 100%;
	height: 10rem;
}
.swiper-container img{
	width: 100%;
	height: 10rem;
}
.swiper-pagination{
	bottom:0.266666rem;
	width: 100%;
	text-align: right;
	color:#FFFFFF;
	font-size:0.426666rem;
}
.swiper-pagination-fraction, .swiper-pagination-custom, .swiper-container-horizontal > .swiper-pagination-bullets{
	left:-0.533333rem;
}
.goods-name{
	padding:0.533333rem 0.266666rem;
	border-bottom:1px solid #CCCCCC;
	h1{
		font-size:0.533333rem;
		font-weight: 500;
	}
	div{
		padding:0.08rem 0;
		font-size:0.373333rem;
		color: #999999;
	}
}
.goods-price{
	padding:0.533333rem 0.266666rem;
	.oprice{
		color:red;
		span{
			font-size:0.32rem;
		}
	}
	.pprice{
		color:#999999;
		font-size:0.373333rem;
	}
}
footer{
	display: flex;
	justify-content: center;
	align-items: center;
	position: fixed;
	bottom:0;
	left: 0;
	width: 100%;
	height: 1.306666rem;
	border-top:1px solid #cccccc;
	background-color: #fff;
	div{
		width: 50%;
		line-height: 1.306666rem;
		font-size: 0.426666rem;
		text-align: center;
		color:#fff;
		background-color: red;
		&.add-cart{
			background-color: #FF9500;
		}
	}
	
}
</style>

效果图:
在这里插入图片描述

性能优化——keep-alive缓存组件

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值