如下代码供学习交流,免费获取完整代码,请关注文后二维码(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加油站)获取。