Vue 实现商品分类、列表、详情、购物车、搜索(vant)

商品分类Classify:

<template>
	<div>
		
		
		<div style="display: flex;">
			
			<div class="oneNav">
				<!-- vant侧边导航 -->
				<van-sidebar style="height: 617px; white-space: nowrap; overflow-y: scroll;" v-model="activeKey">
					<van-sidebar-item 
					v-for="(item,index) in oneClass" 
					:title="item.cname" 
					@click="oneNav(index)"/>
				</van-sidebar>
				
			</div>
			
			
			<div class="twoNav">
				<!-- vant宫格 -->
				<van-grid :gutter="10" column-num="3" :border="false" icon-size="60px">
				  <van-grid-item  
					v-for="(item,index) in twoClass" 
					:icon="item.scpic" 
					:text="item.subcname" 
					@click="onList(item.subcid)"/>
				</van-grid>
			</div>
			
			
		</div>
		
		
	</div>
</template>

<script>
	export default{
		data(){
			return{
				oneClass:[], //一级分类数据
				activeKey:0,
				twoClass:[] //二级分类数据
			}
		},
		mounted() {
			this.$axios.get('http://api.kudesoft.cn/tdk/category').then(res=>{
				// console.log(res.data.data.data)
				this.oneClass = res.data.data.data
				this.twoClass = this.oneClass[0].subcategories
			})
		},
		methods:{
			oneNav(index){ //点击一级导航切换
				this.$axios.get('http://api.kudesoft.cn/tdk/category').then(res=>{
					// console.log(res.data.data.data)
					this.oneClass = res.data.data.data
					this.twoClass = this.oneClass[index].subcategories
				})
			},
			onList(id){ //点击二级导航跳转列表页
				this.$router.push({
					path:'/list',
					query:{
						id
					}
				})
			}
		}
	}
</script>

<style scoped>
	.van-sidebar::-webkit-scrollbar {
		display: none;
	}
	
</style>

商品列表List:

<template>
	<div>
		
		<!-- vant搜索 -->
		<div class="list-nav">
			<van-search @click="toSearch" v-model="kw" shape="round" placeholder="请输入搜索关键词">
				
				<template #left>
					<van-icon @click="back" style="margin-right: 5px;" size="22px" name="arrow-left" />
				</template>
				
			</van-search>
		</div>
		
		<!-- 排序 -->
		<div class="list-sort">
			<div @click="onSort" :class="{'active':isActive==0}">综合排序</div>
			
			<div @click="saleSort" :class="{'active':isActive==1}">销量</div>
			
			<div @click="priceSort" style="display: flex;">
				<div>价格</div>
				<div style="margin-left: 5px;">
					<div :class="{'active':isActive==2}" class="iconfont icon-jiantou"></div>
					<div :class="{'active':isActive==3}" class="iconfont icon-jiantouxia"></div>
				</div>
			</div>
			
			<div><!-- 下拉菜单 -->
				<van-dropdown-menu>
				  <van-dropdown-item v-model="value1" :options="option1" @change="screen" />
				</van-dropdown-menu>
			</div>
			
		</div>
		
		
		<!-- vant骨架屏 -->
		<van-skeleton v-for="i in 18" title :row="3" :loading="list.length<=0" style="background-color: white;"/>
		
		<div style="margin-top: 96px;">
			<!-- 商品卡片 -->
			<van-card
				v-for="(item,index) in list"
				:tag="item.shopType == 1 ? '天猫':'淘宝'"
				:price="item.actualPrice"
				:title="item.title"
				:thumb="item.mainPic"
				@click="toDetails(item.id)">
				
				<template #num>
					<span>30天销量:{{item.monthSales}}</span>
				</template>
			</van-card>
		</div>
		
	</div>
</template>

<script>
	export default{
		data(){
			return{
				kw:'',
				list:[],
				value1: -1,
				option1: [
					{ text: '店铺类型', value: -1 },
					{ text: '淘宝', value: 0 },
					{ text: '天猫', value: 1 }
				],
				isActive:-1 //0综合排序,1销量,2价格升序,3价格降序
			}
		},
		mounted() {
			this.kw = this.$route.query.kw //把搜索页面搜索的值传过来
			
			let id = this.$route.query.id
			this.$axios.get('http://api.kudesoft.cn/tdk/goods',{
				params:{
					pageId:1,
					subcid:id
				}
			}).then(res=>{
				// console.log(res.data.data.data.list)
				let list = res.data.data.data.list
				if(this.kw == '' || this.kw == undefined){
					this.list = list
				}else{
					list.map(item=>{
						if(item.title.includes(this.kw)){
							this.list.push(item)
						}
					})
				}
			})
		},
		methods:{
			back(){ //返回分类页面
				this.$router.push({
					path:'/classify'
				})
			},
			toSearch(){ //跳转到搜索页面
				this.$router.push({
					path:'/search'
				})
			},
			toDetails(id){ //跳转到详情页面
				this.$router.push({
					path:'/details',
					query:{
						id
					}
				})
			},
			priceSort(){ //价格排序
				if(this.isActive < 2){
					this.isActive = 2
					this.list.sort((a,b)=>{
						return a.actualPrice - b.actualPrice
					})
				}else if(this.isActive == 2){
					this.isActive = 3
					this.list.sort((a,b)=>{
						return b.actualPrice - a.actualPrice
					})
				}else if(this.isActive == 3){
					this.isActive = 2
					this.list.sort((a,b)=>{
						return a.actualPrice - b.actualPrice
					})
				}
			},
			onSort(){ //综合排序
				this.isActive = 0
				this.list.sort((a,b)=>{
					return b.shopLevel - a.shopLevel
				})
			},
			saleSort(){ //销量排序
				this.isActive = 1
				this.list.sort((a,b)=>{
					return b.monthSales - a.monthSales
				})
			},
			screen(value){ //筛选
				this.isActive = -1
				this.list = []
				
				if(value == -1){
					this.$axios.get('http://api.kudesoft.cn/tdk/goods').then(res=>{
						this.list = res.data.data.data.list
					})
				}else{
					this.$axios.get("http://api.kudesoft.cn/tdk/goods").then(res=>{
						let list = res.data.data.data.list
						list.map(item=>{
							if(item.shopType == value){
								this.list.push(item)
							}
						})
					})
				}
			}
		}
	}
</script>

<style scoped>
	.list-title{
		 display: -webkit-box;
		 -webkit-box-orient: vertical;
		 -webkit-line-clamp: 2;
		 overflow: hidden;
	}
	.list-nav{
		width: 100%;
		position: fixed;
		top: 0;
		left: 0;
		z-index: 99;
	}
	.iconfont{
		font-size: 8px;
		margin: 0 3px;
	}
	.active{
		color: red;
	}
	.list-sort{
		position: fixed;
		top: 54px;
		left: 0;
		z-index: 99;
		width: 100%;
		background-color: #FFFFFF;
		display: flex;
		justify-content: space-around;
		align-items: center;
		margin-top: -1px;
		font-weight: 300;
	}
</style>


商品详情Details:

<template>
	<div>
		
		<!-- element-ui返回顶部 -->
		<el-backtop :bottom="100" :right="0">
		   <div
		     style="{
		       height: 100%;
		       width: 100%;
		       background-color: #f2f5f6;
		       box-shadow: 0 0 6px rgba(0,0,0, .12);
		       text-align: center;
		       line-height: 40px;
		       color: #000000;
			   border-radius: 50%;
		     }"
			>
		    <span class="el-icon-upload2"></span>
		   </div>
		</el-backtop>
		
		
		<div>
			<!-- vant轮播 -->
			<div style="background-color: #FFFFFF; border-radius: 0 0 15px 15px; margin-bottom: 15px;">
				<van-swipe class="my-swipe" indicator-color="white">
				  <van-swipe-item v-for="(item,index) in details.imgs">
					  <img :src="item" width="100%">
				  </van-swipe-item>
				</van-swipe>
				
				<div style="padding: 10px 10px;">
					<div style="display: flex; justify-content: space-between;">
						<span style="color: #F2270C;"><span style="font-size: 30px;">{{details.actualPrice}}</span></span>
						<img :src="details.shopLogo" width="30px" height="30px">
					</div>
					
					<div>
						<span style="margin-right: 5px; font-size: 12px; background-color: #FF0000; color: white; padding: 2px 2px; border-radius: 2px;">{{details.shopName}}</span>
						<span style="font-weight: 700;">{{details.title}}</span>
					</div>
				</div>
			</div>
			
			<div>
				<div v-for="(item,index) in details.detailPics">
					<img :src="item.img" width="100%">
				</div>
			</div>
			
		</div>
		
		
		<div style="height: 50px;"></div>
		<!-- vant商品导航 -->
		<van-goods-action>
		  <van-goods-action-icon icon="chat-o" text="客服" dot />
		  <van-goods-action-icon icon="cart-o" text="购物车" :badge="this.carts.length" @click="toCarts"/>
		  <van-goods-action-icon icon="shop-o" text="店铺" />
		  <van-goods-action-button @click="addCart" type="warning" text="加入购物车" />
		  <van-goods-action-button type="danger" text="立即购买" />
		</van-goods-action>
		
		
		
	</div>
</template>

<script>
	import Vue from 'vue';
	import { Toast } from 'vant';
	Vue.use(Toast);
	export default{
		data(){
			return{
				details:[],
				carts:[] //购物车商品
			}
		},
		created() {
			let carts = localStorage.carts
			if(carts){
				this.carts = JSON.parse(carts)
			}
		},
		mounted() {
			let id = this.$route.query.id
			this.$axios.get('http://api.kudesoft.cn/tdk/details',{
				params:{
					id:id
				}
			}).then(res=>{
				// console.log(res.data.data.data)
				this.details = res.data.data.data
				this.details.imgs = this.details.imgs.split(',')
				//this.details.detailPics = this.details.detailPics.split(',')
				this.details.detailPics = JSON.parse(this.details.detailPics)
			})
		},
		methods:{
			toCarts(){ //跳转购物车页面
				this.$router.push({
					path:'/carts'
				})
			},
			addCart(){ //添加购物车
				Toast.success('加入购物车成功');
				
				let rel = true
				this.carts.map(item=>{
					if(item.data.id == this.details.id){
						item.num++;
						rel = false;
					}
				})
				
				if(rel){
					this.carts.push({
						data:this.details,
						num:1
					})
				}
				
				localStorage.carts = JSON.stringify(this.carts)
			}
		}
	}
</script>

<style>
</style>

购物车Carts:

<template>
	<div>
		
		<!-- vant空状态 -->
		<van-empty v-show="isShow" description="购物车目前还没有商品" image="https://img.yzcdn.cn/vant/custom-empty-image.png">
		  <van-button round type="danger" class="bottom-button" @click="gotoClassify">
		    去购物
		  </van-button>
		</van-empty>
		
		
		<div v-for="(item,index) in carts">
			<!-- vant复选框组 --> <!-- vant布局 --> <!-- vant滑动单元格 --> 
			<!-- vant商品卡片 --> <!-- vant步进器 -->
			<van-checkbox-group v-model="result" @change="onChecked">
				<van-row style="background-color: white;">
					
				  <van-col span="2" style="margin-top: 35px;">
					
					<van-checkbox :name="item"></van-checkbox>
				  
				  </van-col>
				  
				  <van-col span="22">
					
					  <van-swipe-cell>
					  	
					    <van-card
					      :price="item.data.actualPrice"
					      :desc="item.data.desc"
					      :title="item.data.dtitle"
						  :thumb="item.data.mainPic"
					      class="goods-card"
					  	>
					    
					  	  <template #num>
					  		<van-stepper v-model="item.num" @change="onNum"/>
					  	  </template>
					  	  
					    </van-card>
					    
					    <template #right >
					      <van-button @click="del(item,index)" square text="删除" type="danger" class="delete-button" />
					    </template>
					    
					  </van-swipe-cell>
					  
				  </van-col>
				  
				</van-row>
			</van-checkbox-group>
			
			
		</div>
		
		<!-- vant提交订单栏 -->
		<van-submit-bar :price="total" button-text="提交订单">
		  <van-checkbox v-model="checkedAll" @click="onAll">全选</van-checkbox>
		</van-submit-bar>
		
		
	</div>
</template>

<script>
	export default {
		data(){
			return{
				carts:[], //添加到购物车的商品
				result:[], //所有复选框选中的商品
				checkedAll:false, //全选的状态
				total:0, //总价
				isShow:true
			}
		},
		created() {
			let carts = localStorage.carts
			if(carts){
				this.carts = JSON.parse(carts)
			}
			
			if(this.carts.length > 0){ //显示或隐藏空状态
				this.isShow = false
			}else{
				this.isShow = true
			}
		},
		methods:{
			onNum(){ //商品数量发生变化时触发
				this.onChecked()
				localStorage.carts = JSON.stringify(this.carts)
			},
			onChecked(){ //点击复选框选中商品并计算总价
				this.total = 0
				this.result.map(item=>{
					this.total += item.data.actualPrice*100*item.num
				})
				
				if(this.result.length == this.carts.length){
					this.checkedAll = true
				}else{
					this.checkedAll = false
				}
				
			},
			onAll(){ //点击全选按钮
				if(this.checkedAll){ //如果为true的话全部选中,否则全不选
					this.result = this.carts
				}else{
					this.result = []
				}
			},
			del(item,index){ //删除
				if(this.result.includes(item)){
					this.$notify({ type: 'danger', message: '删除前请取消选中' });
				}else{
					this.carts.splice(index,1)
					this.checkedAll = this.result.length == this.carts.length
					localStorage.carts = JSON.stringify(this.carts)
				}
				
				if(this.carts.length > 0){ //显示或隐藏空状态
					this.isShow = false
				}else{
					this.isShow = true
					this.checkedAll = false
				}
				
			},
			gotoClassify(){ //跳转到分类页
				this.$router.push({
					path:'/classify'
				})
			}
		}
	}
</script>

<style scoped="scoped">
	.goods-card {
	   background-color: white;
	}
	
	.delete-button {
	   height: 100%;
	}
	
	.bottom-button {
	  width: 180px;
	  height: 40px;
	}
</style>

搜索Search:

<template>
	<div>
		
		<!-- vant搜索 -->
		<van-search @input="showSearch" @search="onSearch" autofocus show-action shape="round" v-model="kw" placeholder="请输入搜索关键词">
			
			<template #left>
				<van-icon @click="back" style="margin-right: 5px;" size="22px" name="arrow-left" />
			</template>
			
			<template #action>
				<van-button @click="onSearch" size="small" type="danger" style="border-radius: 5px; font-size: 14px;">搜索</van-button>
			</template>
			
		</van-search>
		
		<!-- 搜索记录 -->
		<div v-show="isShow">
			<div style="display: flex; justify-content: space-between; padding: 5px;">
				<div>
					搜索记录:
				</div>
				
				<div>
					<van-icon @click="onDel" size="18px" name="delete" />
				</div>
			</div>
			
			<div>
				<van-tag style="margin: 5px;" v-for="(item,index) in saveList">{{item}}</van-tag>
			</div>
		</div>
		
		<!-- 搜索提示 -->
		<van-cell-group v-show="!isShow">
		  <van-cell v-for="(item,index) in showList" :title="item.dtitle" />
		</van-cell-group>
		
	</div>
</template>

<script>
	export default{
		data(){
			return{
				kw:'',
				isShow:true,
				list:[], //所有数据
				saveList:[], //搜索记录的数据
				showList:[] //搜索提示的数据
			}
		},
		created() {
			let saveList = localStorage.saveList
			if(saveList){
				this.saveList = JSON.parse(saveList)
			}
		},
		mounted() {
			this.$axios.get(' http://api.kudesoft.cn/tdk/goods').then(res=>{
				// console.log(res.data.data.data.list)
				this.list = res.data.data.data.list
			})
		},
		methods:{
			back(){ //返回上一级
				window.history.back()
			},
			onSearch(val){ //点击enter和点击搜索时触发
			
				if(val.trim() == ''){ //如果搜索的值为空则不会跳转
					return
				}
			
				this.$router.push({ //点击跳转到列表页,并把输入的值传过去
					path:'/list',
					query:{
						kw:val
					}
				})
				
				if(!this.saveList.includes(val.trim())){ //判断是否重复添加相同记录
					this.saveList.push(val) //把搜索的值添加到搜索记录
					localStorage.saveList = JSON.stringify(this.saveList)
				}
				
			},
			showSearch(){ //输入框内容发生变化时触发
				this.showList = []
				
				this.list.map(item=>{
					if(item.dtitle.includes(this.kw)){
						this.showList.push(item)
					}
				})
				
				if(this.kw.trim() == ''){ //判断显示或隐藏搜索提示
					this.isShow = true
				}else{
					this.isShow = false
				}
			},
			onDel(){ //删除
				this.$dialog.confirm({
				  title: '确定要清空搜索记录吗'
				})
				.then(() => {
				    this.saveList = []
					localStorage.saveList = JSON.stringify(this.saveList)
				})
				.catch(() => {
				    // on cancel
				});
			}
		}
	}
</script>

<style>
</style>

你可能感兴趣的:(Vue项目,vue.js,前端)