如下代码供学习交流,免费获取完整代码,请关注文后二维码(coding加油站)获取。

1.网页作品简介 :

vue实现的化妆品商城系统,有后端项目,可以分别单独使用,加上后端的话就是一个简单的毕业设计,功能实现

​ 1. 验证用户名,验证表格

​ 2. 首页轮播图,下拉刷新页面内容

​ 3. 分类页面点击不同导航栏展示不同内容

​ 4. 商品详情页加入购物车

​ 5. 购物车选择功能

2.知识应用:

能够熟悉Vue的基本语法,v-for,v-if,v-show等相关语法的使用,以及使用了vue-router等相关技术实现了轮播图,商品列表页,商品详情页,购物车界面,登录界面,登录注册,列表选择

3. 内容介绍:
演示视频:

【coding加油站】vue化妆品商城

如下是一些效果图:

 

 

 部分代码如下:

<script>
	//1.导入封装后的接口  
	import {
		getProductListAPI
	} from "@/api/product.js";
	import {
		getCategoryAPI
	} from "@/api/category.js";
	export default {
		data() {
			return {
				productList: [],
				categoryList: [], //类别菜单名称列表,注意其数据结构
				category_id: null,
				activeKey: 0,
				//分页
				pageIndex: 0, //页码  
				pageSize: 10, //页大小      
				pageTotal: 0, //总页数
				loading: false,
				finished: false,
				//下拉刷新状态控制变量
				refreshing: false,
			}
		},
		//生命周期钩子函数,当实例创建好了后被调用,
		created() {
			// 获取左侧导航的分类内容
			getCategoryAPI().then(result => {
				// console.log(result); //调式输出,看数据结构
				this.categoryList = result.data;
				this.category_id = this.categoryList[0].id;
				// this.onLoad();
				this.onRefresh()
			});
		},
		methods: {
			//点击左侧分类
			onClickLeftMenus(category_id) {
				this.category_id = category_id;
				this.productList = []; //清空
				this.onRefresh();
			},
			// 上拉加载,每次加载1页
			onLoad() {
				// 异步更新数据
				this.pageIndex += 1; //页码递增
				let category_id = this.category_id; //商品分类id
				let pageIndex = this.pageIndex;
				let pageSize = this.pageSize; //页大小      
				getProductListAPI({
					category_id,
					pageIndex,
					pageSize
				}).then((result) => {
					console.log(result); //调式输出,看数据结构
					this.pageTotal = result.pageTotal; //总页数
					//如果是正在下拉刷新中
					if (this.refreshing) {
						this.productList = []; //清空
						this.refreshing = false;
					}
					if (result.data.length > 0) {
						this.productList = this.productList.concat(result.data); //数据拼接
					}
					// 设置本次上拉加载状态结束
					this.loading = false;
					// 判断是否数据全部加载完成
					if (this.pageIndex > this.pageTotal) {
						this.finished = true;
					}
				});
			},
			// 下拉刷新,刷新当前分类的商品 ,从第1页开始加载
			onRefresh() {
				this.pageIndex = 0; //重置页码        
				this.finished = false; //重置上拉加载未完成
				// 重新加载数据
				// 将 loading 设置为 true,表示处于加载状态
				this.loading = true;
				this.onLoad();
			},
			//点击右侧商品导航到商品详情
			onDetail(id) {
				this.$router.push({
					name: 'productDetail',
					params: {
						id
					},
				});
			}
		}
	}
</script>
<template>
	<div>
		<van-row type="flex" justify="center" style="background-image: linear-gradient(to bottom, #fff7fb, #fff);">
			<div class="tx">
				<van-image :src="require('@/assets/images/login.png')" width="120px"></van-image>
			</div>
		</van-row>
		<van-cell-group :border="false" class="lb">
			<van-field label="账号" placeholder="请输入账号" v-model="loginForm.name" class="text r1"></van-field>
			<van-field label="密码" placeholder="请输入密码" type="password" v-model="loginForm.password" class="text r2"></van-field>
			<van-button style="margin-top: 45px;border-radius: 50px;" @click="onClickLogin" color="#ffcada" size="large" block>登录</van-button>
			<div class="goto" @click="onClickRegister" style="color: #909090;cursor: pointer;font-size: 14px;">若还没有账号?点击前往注册</div>
		</van-cell-group>
	</div>
</template>

<script>
	import {
		loginAPI
	} from "@/api/user.js"; //导入登录接口
	import * as Auth from "@/utils/auth.js";

	export default {
		name: "login",
		data() {
			return {
				loginForm: {
					name: "", //设置默认值,仅是方便调试
					password: "",
				},
			};
		},
		mounted() {
			//初始赋值 ,从本地存储中获取用户名
			this.loginForm.name = getUserLocal().name;
		},
		methods: {
			//处理用户登录
			onClickLogin() {
				if (this.loginForm.name === "" || this.loginForm.password === "") {
					this.$toast("账号或密码不能为空");
					return;
				}
				let params = this.loginForm;
				loginAPI(params).then(result => {
					this.$toast({
						message: "登录成功!",
						duration: 1000
					});
					//本地保存用户信息(id,name)保存Token
					Auth.setTokenLocal(result.data.token); //保存Token
					Auth.setUserLocal(result.data.user); //保存用户数据
					let toPath = this.$route.params.redirect || "user";
					this.$router.replace({
						path: toPath
					});
				});
			},
			onClickRegister() {
				this.$router.push({
					name: "register"
				});
			}
		},
	};
</script>

<style lang="less" scoped="scoped">
	.tx {
		width: 120px;
		padding: 15px 20px;
		border-radius: 60%;
		background-color: #fafafa;
		margin: 50px 0;
	}

	.lb {
		margin: auto;
		width: 65%;
	}

	.text {
		font-size: 16px;
		padding: 20px 20px;
		background-color: #fafafa;
	}
	
	.r1{
		border-top-left-radius: 10px;
		border-top-right-radius: 10px;
	}
	
	.r2{
		border-bottom-left-radius: 10px;
		border-bottom-right-radius: 10px;
	}
	
	.goto {
		display: block;
		margin-top: 25px;
		text-align: center;
	}
</style>
<template style="background-color: #f6f6f6;">
	<div>
		<div v-if="cartList.length==0">
			<van-cell-group :border="false">
				<van-cell value="看看别人购物车都要啥?" is-link class="cell">
					<template #title>
						<div class="cell_title">
							<van-icon name="cart-circle-o" size="38" />
							<div style="margin-left: 10px;font-size: 16px;font-weight: bold;">购物车抄作业</div>
						</div>
					</template>
				</van-cell>
			</van-cell-group>
			<div class="cart_empty">
				<van-image :src="require('@/assets/images/shopcart_empty.png')" width="45%"></van-image>
				<div style="color: #666;">购物车竟然是空的</div>
				<div style="color: #aaa;">再忙,也要记得买点什么犒劳自己~</div>
				<div style="margin-top: 30px;">
					<van-button round plain hairline color="#000">逛逛秒杀</van-button>
					<van-button round plain hairline color="#000" style="margin-left: 30px;">看看收藏</van-button>
				</div>
			</div>
		</div>
		<!-- 全选 清空 -->
		<van-cell-group v-if="cartList.length>0" :border="false" style="margin-bottom: 15px;">
			<van-cell class="cell">
				<template #title>
					<div class="cell_title">
						<van-checkbox checked-color="#cb8081" icon-size="18" v-model="isCheckedAll"
							@click="onSelectAll">全选
						</van-checkbox>
					</div>
				</template>
				<div @click="onClickDeleteAll" style="cursor: pointer;color: #000;">清空</div>
			</van-cell>
		</van-cell-group>
		<!-- 商品列表区域 -->
		<div v-if="cartList.length>0" v-for="(item, i) in cartList" :key="i">
			<van-swipe-cell>
				<van-row type="flex" align="center" justify="center" class="cart_box">
					<van-col span="2">
						<!-- 复选框 -->
						<van-checkbox v-model="item.is_checked" @change="onCheckedChange(item)"
							checked-color="#cb8081" />
					</van-col>
					<van-col span="5">
						<!-- 中间商品图片 -->
						<van-image width="78px" height="78px" fit="cover" :src="APIDomainName + item.img"
							radius="8px" />
					</van-col>
					<van-col span="15" style="height: 84px;">
						<van-row class="van-multi-ellipsis--l2 cart_title">{{ item.title }}</van-row>
						<van-row type="flex" align="center">
							<van-col span="8" class="cart_price">¥{{ item.price }}</van-col>
							<van-col span="16" class="opration">
								<van-stepper v-model="item.count" @change="onCountChanged(item)" integer
									style="font-weight: ;" />
							</van-col>
						</van-row>
					</van-col>
				</van-row>
				<template #right>
					<van-button @click.prevent="onClickDeleteCartItem(item.id)" color="#fff" style="height: 100%;">
						<van-icon name="delete-o" size="25" color="#000" />
					</van-button>
				</template>
			</van-swipe-cell>
		</div>
		<!-- 商品结算区域 -->
		<van-row v-if="cartList.length>0" type="flex" align="center" class="cart_bottom">
			<van-col span="16" style="padding-left: 25px;text-align: left;">
				<div v-if="getCheckedCount>0">
					<span style="color: #666;">已勾选{{ getCheckedCount }}件,</span>
					<span
						style="font-size: 18px;font-weight: bold;color: #EF4141;">¥{{ getCheckedAmount }}</span></span>
					<div style="font-size: 13px;color: #aaa;margin-top: 10px;">总计不含运费</div>
				</div>
				<div v-if="getCheckedCount==0">
					<span style="font-size: 18px;font-weight: bold;">合计:¥0</span>
				</div>
			</van-col>
			<van-col span="8" style="text-align: right;padding-right: 25px;">
				<van-button round size="large" color="#cb8081">结算</van-button>
			</van-col>
		</van-row>
	</div>
</template>

<script>
	//导入接口
	import {
		deleteCartAllAPI,
		updateCartCheckedAllAPI,
		getCartListAPI, //获取列表
		updateCartCountAPI, //更新数量
		updateCartCheckedAPI, //更新是否勾选
		deleteCartItemAPI, //删除购物车项
	} from "@/api/cart.js";

	export default {
		name: "Shopcart",
		data() {
			return {
				cartList: [], //购物车列表
				isCheckedAll: false, //定义属性变量
			};
		},

		//实例的生命周期函数,实例创建后被调用
		created() {
			this.getCartData(); //初始化购物车数据
		},
		computed: {
			getCheckedCount() {
				let sum = 0;
				this.cartList.forEach((item) => {
					if (item.is_checked) sum += 1;
				});
				return sum;
			},

			getCheckedAmount() {
				let amount = 0;
				this.cartList.forEach((item) => {
					if (item.is_checked) amount += item.price * item.count;
				});
				return amount;
			},
			getCheckedAll() {
				return this.cartList.length == this.getCheckedCount ? true : false;
			}
		},
		created() {
			this.getCartData();
		},
		methods: {
			//获取用户购物车数据			
			getCartData() {
				this.cartList = []; //清空				
				getCartListAPI().then(result => {
					this.cartList = result.data;
					this.isCheckedAll = this.getCheckedAll; // 重置isCheckedAll属性值			
				}).catch(() => {});
			},

			//触发更改购物商品选中状态
			onCheckedChange(item) {
				let id = item.id;
				let is_checked = item.is_checked == true ? 1 : 0;
				let params = {
					id,
					is_checked
				};
				updateCartCheckedAPI(params).then(() => {
					this.isCheckedAll = this.getCheckedAll; // 是否全选
				}).catch(() => {});
			},

			//触发更改购物商品数量
			onCountChanged(item) {
				let params = {
					id: item.id,
					count: item.count
				};
				updateCartCountAPI(params).then(() => {});
			},

			//触发删除购物商品
			onClickDeleteCartItem(id) {
				let ids = id;
				deleteCartItemAPI(ids).then(() => {
					this.getCartData(); //刷新列表数据
				});
			},
			//触发全选/全不选			
			onSelectAll() {
				let is_checked = this.isCheckedAll == true ? 1 : 0;
				updateCartCheckedAllAPI(is_checked).then(() => {
					this.getCartData();
				});
			},
			//触发清空			
			onClickDeleteAll() {
				this.$dialog.confirm({
					message: '客官,您确定清空购物车吗?'
				}).then(() => {
					deleteCartAllAPI().then(() => {
						this.getCartData();
					});
				})
			},
		},

	}
</script>

<style>
	.cart_empty {
		margin-top: 35px;
		text-align: center;
		line-height: 36px;
	}

	.cell_title {
		height: 100%;
		display: flex;
		justify-content: flex-start;
		align-items: center;
	}

	.cell {
		align-items: center;
		width: 95%;
		margin: auto;
		margin-top: 20px;
		border-radius: 10px;
		background-color: #f8ebea;
	}

	.cart_box {
		width: 95%;
		margin: auto;
		margin-bottom: 15px;
		background-color: #fafafa;
		padding-top: 10px;
		padding-bottom: 10px;
		border-radius: 10px;
	}

	.cart_price {
		color: #EF4141;
		padding-left: 10px;
	}

	.van-stepper__minus {
		border-top-left-radius: 50%;
		border-bottom-left-radius: 50%;
	}

	.van-stepper__minus--disabled {
		border-top-left-radius: 50%;
		border-bottom-left-radius: 50%;
	}

	.van-stepper__plus {
		border-top-right-radius: 50%;
		border-bottom-right-radius: 50%;
	}

	.cart_title {
		padding: 5px 5px;
		font-size: 15px;
		font-weight: bold;
		line-height: 21px;
		height: 40px;
	}

	.opration {
		padding-right: 10px;
		display: flex;
		align-items: center;
		justify-content: flex-end;
	}

	.cart_bottom {
		position: fixed;
		bottom: 0;
		width: 100%;
		height: 70px;
		margin-bottom: 50px;
		background-color: #f8ebea;
	}
</style>

免费获取完整代码,请关注公众号(coding加油站)获取。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐