目录
一、前言
二、项目效果图及实现关键点
1.首页
2.分类
3.购物车
4.我的
5.登录、注册
6.商品详情
7.订单结算,动态生成订单
8.订单
9.收货地址
10. 商品搜索
三、代码关键
1.数据分离维护
2.购物车实现完整代码
四、总结
五、其他作品集合
一、前言
项目在线预览地址:点击预览
vant2开发文档官网:点击访问
二、项目效果图及实现关键点
1.首页
- 头部分离vue组件实现;
- 轮播图使用vant2的swipe轮播,很简单,照搬官方例子就行;
- 分类、商品列表布局使用vant2的Grid布局,真是个好东西,布局搞定其他都简单;
- 菜单采用vant2的Tabbar,当前选中的菜单记得在页面刷新的时候也要重新标记好;
2.分类
分类使用vant2的TreeSelect组件实现,通过自定义样式处理。
3.购物车
购物车动态数据实现,可进行增、删、改、查,通过商品详情页面添加购物车,同时支持多商品同时下单结算。
多商品同时结算:
生成订单:
购物车删除:
4.我的
未登录:
已登录:
5.登录、注册
完整登录注册功能,注册和登录信息寄存在本地浏览器,账号名称唯一。
6.商品详情
商品详情轮播图与首页差不多一样,底部按钮使用vant2的GoodAction组件,如下图,有多种实现效果:
商品信息面板半窗采用vant2的sku组件,如下图:
7.订单结算,动态生成订单
获取默认地址,没有默认地址则取最新一个地址,没有地址则提示去完善地址,同时可重新选择地址提交订单。提交按钮使用SubmitBar,如下图:
8.订单
支持多商品组合订单
9.收货地址
地址列表采用vant2的地址列表AddressList,所有地址动态增、删、改、查,寄存在本地浏览器缓存里,包含全国地区数据选择,地区数据已完整,香港、澳门、台湾的都有。
10. 商品搜索
无商品
商品名称模糊动态搜索:
三、代码关键
1.数据分离维护
所有需要动态的重要数据全部放在json文件进行维护管理,如下图:
数据json代码实现:
{
"banners":[
"fac6082a5a2e27bf003163c8ea9ae150.jpg",
"387d1bad240308862741ced9bcaf2f2a.jpg",
"6e95960cdf5776933de70392441d6357.jpg",
"744dd4674e7e07fbd763fb7e98e753a6.jpg"
],
"types": [
{"id": 1,"name":"口红","img": "b1749080cf5bbc4dfebff83013bbebaf.jpg"},
{"id": 2,"name":"戒指","img": "eb5024fe-dfe3-6e53-3e18-675bef5fa06e.jpg"},
{"id": 3,"name":"护肤品","img": "69c250436545049ccab81c3e32033cf2.jpg"},
{"id": 4,"name":"眼镜","img":"e8bc849a-0a3b-21a0-6810-7da3a3903dee.jpg"},
{"id": 5,"name":"腕表","img": "0434594382110f3bd15c90f040d5d542.jpg"},
{"id": 6,"name":"香水","img": "64f3988b6216e4c1ab62a7f50df3e816.jpg"}
],
"products": [
{"id":1,"productName":"香奈儿魅力精萃唇膏","des":"ROUGE ALLURE L'EXTRAIT","img":"202304171628_6486482f87e32aa3b03cfab5928831b0.jpg",
"price":470,
"originalPrice":667,
"stockNum":888,
"imgList": [
"202305101037_1f484e7b75d7eb9a5ec2a002b37b881d.jpg",
"202304171640_6e00669f151572b9e71c91403adb9eb5.jpg",
"202304171640_bdb96c131ce974b8022dfeed37f74a29.jpg",
"202304171640_22905a1bb20af9943c279d66a9c7b0b6.jpg"
],
"score": 4,
"saleNumMonth": 1000,
"saleNumTotal": 1000,
"types":[
{"name":"色号","items":[{"id":1,"name":"812"},{"id":2,"name":"814"},{"id":3,"name":"817"},{"id":4,"name":"818"},{"id":5,"name":"822"},{"id":6,"name":"827"}]}
],
"typeId":[6]
},
{"id":2,"productName":"香奈儿可可小姐润唇膏","des":"ROUGE COCO BAUME","img":"202303281131_cf3ff6ce70177560f3b9f95bd48fc575.jpg",
"price":380,
"originalPrice":499,
"stockNum":1000,
"imgList": [
"202306131549_93005c7e29792ec7f5532fc766f18cd8.jpg",
"202303281129_034065679f1bb313e22bcc38735c3e95.jpg",
"202303281129_8924da3d425a22831c3dc0c4298af762.jpg",
"202303281129_4c4ae6ef811308af527b950e148813b3.jpg",
"202303281129_bd1862a81b59b6b566469bac60decc0d.jpg"
],
"score": 4,
"saleNumMonth": 344,
"saleNumTotal": 32322,
"types":[
{"name":"色号","items":[{"id":1,"name":"912 - DREAMY WHITE"},{"id":2,"name":"914 - NATURAL CHARM"},{"id":3,"name":"916 - FLIRTY CORAL"},{"id":4,"name":"918 - MY ROSE"},{"id":5,"name":"920 - IN LOVE"},{"id":6,"name":"922 - PASSION PINK"}]}
],
"typeId":[7]
},
{"id":3,"productName":"香奈儿五号香水(经典)","des":"N°5","img":"d6354c72c3c1119fa59453dd3a64701e.jpg",
"price":1690,
"originalPrice":1999,
"stockNum":1500,
"imgList": [
"75215921cc17d3a0458da443af3d274e.jpg",
"4896d9eff372e50f62fd914c94c97558.jpg",
"41081e06f6b3f60851325319544c04cf.jpg",
"3e97907814eb90cb9ab95bbfad64f98f.jpg"
],
"score": 4,
"saleNumMonth": 6565,
"saleNumTotal": 54665,
"types":[
{"name":"规格","items":[{"id":1,"name":"10ml"},{"id":2,"name":"20ml"},{"id":3,"name":"50ml"},{"id":4,"name":"100ml"},{"id":5,"name":"200ml"}]}
],
"typeId":[5]
},
{"id":4,"productName":"香奈儿可可小姐柔肤精华油","des":"COCO MADEMOISELLE","img":"202212232345_1322e81f2f5384fd88baa8c60b5cad4e.jpg",
"price":680,
"originalPrice":750,
"stockNum":2000,
"imgList": [
"202212232345_1322e81f2f5384fd88baa8c60b5cad4e.jpg",
"202302031954_d44c662e5dfb997c7f021db87c349c4c.jpg",
"202212111657_a3e16b20bdb358caafd1b8fbd9b5a94d.jpg",
"202212111657_d249c106c4388474add1fbe6b9dd44cc.jpg"
],
"score": 5,
"saleNumMonth": 32,
"saleNumTotal": 1430,
"types":[
{"name":"规格","items":[{"id":1,"name":"10ml"},{"id":2,"name":"20ml"},{"id":3,"name":"50ml"},{"id":4,"name":"100ml"},{"id":5,"name":"200ml"}]}
],
"typeId":[7]
},
{"id":5,"productName":"COCO CRUSH戒指","des":"菱格纹图案,标准款,BEIGE米色18K金","img":"202212232348_5facedab702fee101581c9124af1b89d.jpg",
"price":22800,
"originalPrice":25888,
"stockNum":300,
"imgList": [
"202305301454_fcb43117eddca37188ba875ac35e76d3.jpg",
"202212111740_786c1b111adb507d4c3c0a423be5cf78.jpg",
"202212111740_9ce67aefdbdc18c364190ed498acc467.jpg",
"202212111657_fa3d08b6d3daafa90b052e4bde19e8d6.jpg"
],
"score": 4,
"saleNumMonth": 676,
"saleNumTotal": 5456,
"types":[],
"typeId":[1,2]
},
{"id":6,"productName":"ETERNAL N°5戒指","des":"白18K金,镶嵌钻石","img":"202210262012_94dd4ca657adcebec0d11ea09dac8a03.png",
"price":73300,
"originalPrice":90000,
"stockNum":600,
"imgList": [
"202306181754_e19cc96f9c55cae727066288c0d734da.jpg",
"202211010128_4c6c947ef94f306bc6a9a06a80c1108b.jpg",
"202211021052_0fdf3fbcbbccfed6930b4e0515666f45.jpg",
"202211010128_f38b878c9fea6c800c68305980858ae5.jpg"
],
"score": 4,
"saleNumMonth": 676,
"saleNumTotal": 5456,
"types":[],
"typeId":[1,2]
},
{"id":7,"productName":"矩形框太阳眼镜","des":"黑与金. 镜片:灰, 渐变","img":"bec639601906ed7649970c6ab311f992.png",
"price":3700,
"originalPrice":3999,
"stockNum":999,
"imgList": [
"bec639601906ed7649970c6ab311f992.png",
"0db739c3242fd840db5b4a7d00f5dc43.jpg",
"2f3afbb2c3c64643b64194610e83795f.jpg",
"960cec45d7ebadfcf4d1a73b32d26460.jpg"
],
"score": 4,
"saleNumMonth": 676,
"saleNumTotal": 5456,
"types":[
{"name":"版型","items":[{"id":1,"name":"国际款"},{"id":2,"name":"亚洲款"}]}
],
"typeId":[4]
},
{"id":8,"productName":"矩形框太阳眼镜","des":"醋酯纤维与小牛皮 黑与金. 镜片:灰, 渐变","img":"202304071912_6cc07289d1a7d050d24e3fedf1f73086.png",
"price":3500,
"originalPrice":3700,
"stockNum":3000,
"imgList": [
"202304071912_6cc07289d1a7d050d24e3fedf1f73086.png",
"202304071915_53924e4cfb904562a85541917d3cdb48.jpg",
"202304071915_199c4b55a9a7a33c5e7d7372a6e5b41e.jpg",
"202304071915_4c19387a6a6062c50d506ba9a3018ebb.jpg"
],
"score": 4,
"saleNumMonth": 676,
"saleNumTotal": 5456,
"types":[
{"name":"版型","items":[{"id":1,"name":"国际款"},{"id":2,"name":"亚洲款"}]}
],
"typeId":[4]
},
{"id":9,"productName":"PREMIÈRE ICONIC CHAIN腕表","des":"精钢和红色皮革,白色珍珠母贝表盘","img":"202305021000_3f5df7a23d9a7f11697776e59e3a10d0.png",
"price":40500,
"originalPrice":45000,
"stockNum":100,
"imgList": [
"202305021000_3f5df7a23d9a7f11697776e59e3a10d0.png",
"202305031022_931bdd7f5953d70a1dcd29c10bf4895d.jpg"
],
"score": 4,
"saleNumMonth": 676,
"saleNumTotal": 5456,
"types":[
{"name":"尺寸","items":[{"id":1,"name":"130-142毫米"},{"id":2,"name":"143-155毫米"},{"id":3,"name":"156-168毫米"},{"id":4,"name":"169-181毫米"}]}
],
"typeId":[1,3]
},
{"id":10,"productName":"J12腕表,33毫米","des":"黑色精密陶瓷和精钢,钻石时标","img":"202211292343_1fb2e2ce696643e2e9e863f69cdaf781.png",
"price":56300,
"originalPrice":59999,
"stockNum":50,
"imgList": [
"202211292343_1fb2e2ce696643e2e9e863f69cdaf781.png",
"202302061943_72057977217166d278be977bd2c10fd8.jpg",
"202212111628_736aa5a62bc78ce8814179aa29dbdb99.jpg",
"202212111628_1c65544f3f6f8c51b892c5fc34bfcb2e.jpg"
],
"score": 4,
"saleNumMonth": 676,
"saleNumTotal": 5456,
"types":[
{"name":"尺寸","items":[{"id":1,"name":"130-142毫米"},{"id":2,"name":"143-155毫米"},{"id":3,"name":"156-168毫米"},{"id":4,"name":"169-181毫米"}]}
],
"typeId":[1,3]
},
{"id":11,"productName":"LA MOUSSE CLARIFIANTE","des":"香奈儿柔和净透焕肤水","img":"202212261430_13670e73571ce4136e783f253528ee3b.png",
"price":550,
"originalPrice":650,
"stockNum":777,
"imgList": [
"202305291820_498513d1b3cede830ed4186e7dc36be0.jpg",
"202212272143_aa64d8dc876692e82066a4657243fe52.jpg",
"202212272143_1cdfbb50d91bd8e51c14dd27a5570bfd.jpg",
"202212271141_49e070e64dfc329351a9258803105ffa.jpg"
],
"score": 4,
"saleNumMonth": 676,
"saleNumTotal": 5456,
"types":[
{"name":"规格","items":[{"id":1,"name":"150ml"},{"id":2,"name":"200ml"},{"id":3,"name":"250ml"},{"id":4,"name":"500ml"}]}
],
"typeId":[7]
}
],
"productTypes":[
{"id":1,"text":"精品"},
{"id":2,"text":"高级珠宝"},
{"id":3,"text":"腕表"},
{"id":4,"text":"眼镜"},
{"id":5,"text":"香水"},
{"id":6,"text":"彩妆"},
{"id":7,"text":"护肤品"}
],
"searchRecommend":[
{"name":"戒指"},
{"name":"腕表"},
{"name":"眼镜"},
{"name":"香水"}
]
}
2.购物车实现完整代码
<template>
<div style="font-size: 14px;">
<div id="goods">
<div id="emptyCart" v-if="cartList.length === 0">
<p id="empty">购物车是空的</p>
<a @click="toType" class="" id="goShopping">去逛逛</a>
</div>
<div class="goods-list" v-for="(item,index) in cartList" :key="index">
<a class="select">
<van-checkbox v-model="item.checked" @change="selected(item)" checked-color="#ee0a24"> </van-checkbox>
</a>
<div class="goods-img" @click="productDetail(item)">
<img :src="require('../assets/img/'+item.img)">
</div>
<div class="goods-info">
<p @click="productDetail(item)">{{item.productName}}</p>
<div class="goods-count">
<p @click="productDetail(item)">¥{{item.price}}</p>
<div class="goods-num">
<a>
<img @click="subNum(item)" src="../assets/img/sub.png">
</a>
<span>{{item.num}}</span>
<a>
<img @click="addNum(item)" src="../assets/img/add.png">
</a>
</div>
<div class="delete">
<a @click="delCartSingle(index)">
<img src="../assets/img/del.png">
</a>
</div>
</div>
</div>
</div>
<div id="accounts">
<div id="accounts-content">
<a>
<van-checkbox v-model="allChecked" @change="selectAll" checked-color="#ee0a24" class="allChecked"> </van-checkbox>
<p>全选</p>
</a>
<p>
<span>合计:</span>
<span class="total-price"> ¥{{totalPrice.toFixed(2)}}</span>
</p>
<a v-if="totalNum === 0" style="background: rgb(204, 204, 204);">结算(0)</a>
<a v-else style="background: #ff6034;" @click="toPay">结算({{totalNum}})</a>
</div>
</div>
</div>
</div>
</template>
<script>
import {getStore,setStore,removeStore} from "@/store/store.js";
export default {
data() {
return {
cartList:[],//购物车数据
allChecked: true,//全部选中
totalNum: 0,
totalPrice: 0,
};
},
mounted() {
this.$store.commit('SET_HEADER_FOOTER', {showSearchHeader: true,headerName:'购物车',pageName:'cart',showFooter: true});
this.initCart();
},
methods: {
toType(){//跳转分类
this.$router.push({'path': '/type'});
},
//初始化购物车
initCart(){
let cartList = getStore({name:'cart_list'});
if (cartList) {
cartList.forEach((item,index)=>{
item['checked'] = true;
});
this.allChecked = true;
this.cartList = cartList;
console.log(this.cartList);
this.total();
}
},
//统计
total() {
this.totalNum = 0;
this.totalPrice = 0
this.cartList.forEach((item) => {
item.checked ? (this.totalNum += item.num) : (this.totalNum += 0)
item.checked ? (this.totalPrice += item.num * item.price) : (this.totalPrice += 0);
})
},
//缓存购物车
saveCarToStorage(){
setStore({name:'cart_list',content: this.cartList});
this.total();
console.info(this.cartList);
},
//删除购物车商品 - 单个
delCartSingle(index){
this.$dialog.confirm({
title: '提示',
message: '确定删除?',
})
.then(() => {
if(this.cartList.length > index){
//删除
this.cartList.splice(index,1);
}
try {
//存到缓存
this.saveCarToStorage();
this.$toast.success('删除成功');
} catch (e) {
this.$toast.fail('删除失败');
}
})
.catch(() => {
// on cancel
});
},
//删除购物车商品 - 全部
delCartAll(index){
try {
removeStore({name:'cart_list'});
this.$toast.success('删除成功');
this.initCart();
} catch (e) {
this.$toast.fail('删除失败');
}
},
//商品详情
productDetail(item) {
console.info(item);
this.$router.push({
path:'/productDetail',
query:{
id: item.id
}
})
},
//勾选商品
selected(item){
// item.checked = !item.checked;
if (!item.checked) {
this.allChecked = false;
} else {
let allChecked = true;
this.cartList.forEach((item) => {
if(!item.checked){
allChecked = false;
}
})
this.allChecked = allChecked;
}
this.total();
},
//全选
selectAll(){
if (this.allChecked) {
this.cartList.map((item) => {
this.checked = true;
item.checked = true;
})
} else {
this.checked = false;
this.cartList.map((item) => {
item.checked = false;
})
}
this.total();
},
subNum(item){
let num=item.num;
if(num>1){
num-=1
}
item.num=num;
//存到缓存
this.saveCarToStorage();
},
addNum(item){
let num =item.num;
item.num=num+1;
//存到缓存
this.saveCarToStorage();
},
//结算
toPay() {
let value = '';
this.cartList.forEach((item) => {
if(item.checked){
if(value !== ''){
value += '*';
}
value += item.id + '_' + item.num;
}
});
this.$router.push({
path:'/pay',
query:{
value: value
}
})
},
}
};
</script>
<style scoped>
#goods {
padding: 0rem 0 6.2rem 0;
}
#emptyCart {
background: #e9e9e9;
width: 100vw;
height: 30vw;
display: flex;
justify-content: center;
align-items: center;
}
#empty {
color: #bfbfbf;
margin-right: 0.5rem;
}
li, p, ul {
margin: 0;
}
#goShopping {
color: #696969;
padding: 0.15rem 0.5rem;
border: 0.05rem solid #bfbfbf;
border-radius: 0.2rem;
}
a {
text-decoration: none;
color: #000;
}
#accounts {
position: fixed;
z-index: 2;
bottom: 3.2rem;
left: 0;
background: #fff;
}
#accounts-content, #accounts-content a:first-child {
display: flex;
align-items: center;
}
#accounts-content {
justify-content: space-between;
width: 100vw;
height: 3rem;
box-sizing: border-box;
border-top: 0.03rem solid #e9e9e9;
font-size: .9rem;
}
#accounts-content, #accounts-content a:first-child {
display: flex;
align-items: center;
}
a {
text-decoration: none;
color: #000;
}
#accounts-content img {
height: 1.3rem;
width: 1.3rem;
padding: 0.7rem;
}
.total-price {
color: #ff6700;
font-size: 16px;
font-weight: 600;
}
#accounts-content a:last-child {
width: 30vw;
height: 3rem;
background: #ff6700;
display: flex;
justify-content: center;
align-items: center;
color: #e9e9e9;
text-decoration: none;
}
.goods-list {
display: flex;
align-items: center;
padding: 1rem 0;
border-bottom: 0.3rem solid #e9e9e9;
}
.select {
margin: 0 10px;
}
.goods-img img {
width: 3rem;
height: 3rem;
border: 0.05rem solid #e9e9e9;
padding: 0.5rem;
margin-right: 0.7rem;
display: block;
}
.goods-info {
width: calc(100vw - 9rem);
}
.goods-info>p {
margin: 0 0 1rem 0;
}
.goods-count {
display: flex;
justify-content: space-between;
align-items: center;
}
.goods-count p:first-child {
color: #ff6700;
width: 4rem;
font-size: .9rem;
}
.goods-num {
display: flex;
justify-content: center;
align-items: center;
}
.goods-num img, .goods-num span {
width: 1rem;
height: 1rem;
padding: 0.2rem;
}
.goods-num img {
display: block;
border: 0.03rem solid #d9d9d9;
}
.goods-num span {
display: inline-block;
font-size: 1rem;
line-height: 1rem;
text-align: center;
border-top: 0.03rem solid #d9d9d9;
border-bottom: 0.03rem solid #d9d9d9;
}
.delete img {
display: block;
width: 1.2rem;
height: 1.2rem;
}
.allChecked{
margin: 0 10px;
}
</style>
四、总结
vant是一个对于移动端开发非常友好和方便的前端框架,建议前端开发的同学可以去学习学习。
关注作者,及时了解更多好项目!
作者主页也有更多好项目分享!
获取源码或如需帮助,可通过博客后面名片+作者即可!
五、其他作品集合
- 《vue+elementui实现联想购物商城,样式美观大方》
- 《vue+elementui实现英雄联盟道具城》
- 《vue+elementui实现app布局小米商城,样式美观大方,功能完整》
- 《vue完美模拟pc版快手,实现短视频,含短视频详情播放》
- 《vue+element实现美观大方好看的音乐网站,仿照咪咕音乐网》
- 《vue实现功能完整的购物商城,商品零食、电商通用商城》
- 《vue+element实现蔬菜、水果、电商商城》
- 《vue+element简单实现电商商城网站,模仿小米电商商城》
- 《vue实现美观大方的动漫、cos、帖子类型网站》
- 《vue实现好看的相册、图片网站》
- 《高度仿PC版《微信读书》,好看的小说、读书网站》
- 《vue+element实现非常好看的鲜花网站商城,页面完整,样式美观》
- 《vue+elementui+springboot前后端分离实现通用商城管理后台》
- 《微信小程序日记、微信小程序个人空间、个人日记》
- 《vue+element模仿腾讯视频电影网站》
- 《vue+element高度仿照QQ音乐,完美实现PC端QQ音乐》
- 《vue+element详细完整实现个人博客、个人网站》
- 《vue+elementui+springboot前后端分离实现学校帖子网站,学校大作业》
- 《vue+elementui实现U袋网-完整版》
- 《vue+element+electron仿微信实现》
- 《vue+element模仿电商商城,前后端分离实现,下单微信扫码支付》
- 《electron+vue+elementui实现类似QQ窗口靠边自动边缘隐藏》
- 《微信小程序仿唯聚时代,微信小程序商城》
- 《jquery+bootstrap完整丰富样式开发框架源码,各种现成样式简单易用》
- 《html+css响应式旅游主题网站模板,旅游网站,企业文化新闻类网站》
- 《css+html各种动态、动画、3D相册等7件套》
- 《仿华为电商商城,官网,华为超级新品日demo,大屏霸气且简洁》
- 《vue+element简单实现商城网站首页,模仿电商商城》
- 《vue+elementui实现非常好看的博客、网站首页,网站模板》
- 《elementui+vue实现经典管理系统布局框架,拿来即用》
- 《简系统登录页模板html+vue+elementui》
- 《vue+elementui完美实现博客、网站、个人网站,高仿“张凯博客”》
- 《vue+elementui完美实现后台管理系统的左、右、顶部菜单布局》
- 《html5+css3实现3D正方体动画相册2种+3D旋转木马立体动画相册+表白文字加动画爱心+炫酷万花筒五件套含音乐》
- 《后端使用springboot+maven+shiro+mybatis+mysql,前端使用H-ui.admin_v3.1.3.1,快速实现管理后台功能》
- 《springboot+thymeleaf+maven+html+css实现精美大方好看官网模板完整源码》
- 《html+css实现好友列表,类似QQ群聊成员列表》