1-vant ui框架
2-less-css预编译语言
3-vue
4-vue router
5-vuex
6-axios
7-javascript
8-html5
9-css3
10-vue-cli
11-webpack
1.visua lstudio code,官网https://code.visualstudio.com/
2.navicat
1、用navicat创建一个新的数据库
导入数据库,运行SQL文件
导入mall-server文件下的nideshop.sql文件
导入成功后就会出现这些表(可能要等待一点时间)
** 2、使用visua lstudio code打开文件**
打开红线路径的文件,database是数据库名称、user,password是数据库账户和密码(需要改),prefix是表的前缀
把文件mall和mall-server,分别在终端打开。打开后输入npm install安装两个文件都要安装。(还需要安装vue依赖才能使用)
安装成功后,在mall-server输入npm start,在mall输入npm run serve(要是报错看下面)
如果报错Module build failed (from ./node_modules/babel-loader/lib/index.js)
意思是babel版本冲突
安装npm install @babel/core @babel/preset-env
<script>
//导入接口
import axios from 'axios'
import api from '../assets/config/api'
</script>
接口地址,mall/src/assets/config/api.js
ajax请求,返回后端数据库的数据
1、Search 搜索
打开vant框架网站,基本用法
https://vant-contrib.gitee.io/vant/#/zh-CN/search
mall\src\views的Home.vue
//Home.vue
<van-search placeholder="商品搜索 共239万款好物" input-align='center' v-model="searchData" />
//导入vant
import Vue from 'vue';
import {
Lazyload } from 'vant';
Vue.use(Lazyload);
export default {
name: 'home',
data:function(){
return {
//设置v-mode的值
searchData:"",
data:{
},
}
},
}
2、Swipe 轮播
https://vant-contrib.gitee.io/vant/#/zh-CN/swipe
//Home.vue
<van-swipe :autoplay="3000" :width="375" :height="200">
<van-swipe-item v-for="(image, index) in images" :key="index">
<img class="swiperimg" v-lazy="image.image_url" />
</van-swipe-item>
</van-swipe>
<scrpet>
export default {
data:function(){
return {
searchData:"",
data:{
},
}
},
computed: {
images:function(){
//判断ajax的data.banner是否为数组,是的话返回数组,不是的话返回空数组
if(typeof this.data.banner=='object'){
return this.data.banner
}else{
return []
}
},
}
}
</scrpet>
<style lang="less">
#home{
.swiperimg{
width: 375px;
height: 200px;
}
}
<style>
3、5个图标
Grid 宫格https://vant-contrib.gitee.io/vant/#/zh-CN/grid
<van-grid :column-num='5'>
<van-grid-item v-for="(item,index) in channel" :key="index" :icon="item.icon_url" :text="item.name" />
</van-grid>
<script>
export default {
name: 'home',
data:function(){
return {
searchData:"",
data:{
},
}
computed: {
channel:function(){
//判断ajax的data.channel是否为数组,是的话返回数组,不是的话返回空数组
if(typeof this.data.channel=='object'){
return this.data.channel
}else{
return []
}
},
}
}
</script>
4、品牌制造商直供
图片懒加载
https://vant-contrib.gitee.io/vant/#/zh-CN/swipe
<div class="brandlist">
<!-- Panel 面板 -->
<van-panel title="品牌制造商直供">
<van-grid :column-num="2">
<van-grid-item v-for="(item1,index1) in brandList" :key="index1">
<van-image fit="cover" lazy-load :src="item1.new_pic_url" />
<h4 class="title">{
{
item1.name}}</h4>
<p class="price">{
{
item1.floor_price}}元起</p>
</van-grid-item>
</van-grid>
</van-panel>
</div>
<script>
export default {
name: 'home',
data:function(){
return {
searchData:"",
data:{
},
}
computed: {
brandList:function(){
//判断ajax的data.brandList是否为数组,是的话返回数组,不是的话返回空数组
if(typeof this.data.brandList=='object'){
return this.data.brandList
}else{
return []
}
},
}
}
</script>
<style lang="less">
.brandlist{
.van-grid-item__content{
padding: 0;
}
.van-image{
border: 1px solid #fff;
}
.title{
position: absolute;
top: 20px;
left: 10px;
}
.price{
position: absolute;
top: 40px;
left: 10px;
font-size: 14px;
color:#999 ;
}
</style>
<!-- 新品首发 -->
<div class="newlist">
<van-panel title="品牌制造商直供">
<van-grid :column-num="2">
<van-grid-item v-for="(item2,index2) in newGoodsList" :key="index2">
<van-image fit="cover" lazy-load :src="item2.list_pic_url" />
<h4 class="title" >{
{
item2.name}}</h4>
<p class="price">{
{
item2.retail_price}}元起</p>
</van-grid-item>
</van-grid>
</van-panel>
</div>
<script>
export default {
name: 'home',
data:function(){
return {
searchData:"",
data:{
},
}
computed: {
newGoodsList:function(){
//判断ajax的data.newGoodsList是否为数组,是的话返回数组,不是的话返回空数组
if(typeof this.data.newGoodsList=='object'){
return this.data.newGoodsList
}else{
return []
}
},
}
}
<script>
<style>
.newlist{
.title{
width: 90%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.price{
font-size: 14px;
color:#999 ;
}
}![在这里插入图片描述](https://img-blog.csdnimg.cn/20200911153220161.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpYW9qdWFqdW4=,size_16,color_FFFFFF,t_70#pic_center)
</style>
6、人气面板
Card 卡片
https://vant-contrib.gitee.io/vant/#/zh-CN/card
<div class="hotlist">
<van-panel title="人气推荐">
<van-card v-for="(item3,index3) in hotGoodsList" :key="index3"
:price="item3.retail_price"
:desc="item3.goods_brief"
:title="item3.name"
:thumb="item3.list_pic_url"
/>
</van-panel>
</div>
<script>
export default {
name: 'home',
data:function(){
return {
searchData:"",
data:{
},
}
computed: {
hotGoodsList:function(){
//判断ajax的data.hotGoodsList=是否为数组,是的话返回数组,不是的话返回空数组
if(typeof this.data.hotGoodsList=='object'){
return this.data.hotGoodsList
}else{
return []
}
},
},
}
}
<script>
<style>
.hotlist{
.van-card__content{
justify-content: center;
text-align:left;
}
.van-card__title{
font-weight: 900;
color: #333;
font-size: 14px;
padding: 5px 0;
}
.van-card__price{
color: red;
}
}
</style>
1、创建分类列表的页面
//mall/src/router/index.js
{
path:'/category',
name:'category',
component:Category
},
在mall/scr/views,创建一个文件category.vue
然后导入页面
//mall/src/router/index.js
import Category from '@/views/category'
2、创建Tabbar 标签栏
Tabbar 标签栏https://vant-contrib.gitee.io/vant/#/zh-CN/tabbar#dai-ma-yan-shi
在mall/src/components,创建新的文件tabBtn.vue
//mall/src/components/tabBtn.vue
<template>
<van-tabbar v-model="tabActive">
<van-tabbar-item icon="home-o">首页</van-tabbar-item>
<van-tabbar-item icon="medal-o">专题</van-tabbar-item>
<van-tabbar-item icon="qr">分类</van-tabbar-item>
<van-tabbar-item icon="shopping-cart-o">购物车</van-tabbar-item>
<van-tabbar-item icon="manager-o" badge="20">我的</van-tabbar-item>
</van-tabbar>
</template>
<script>
export default {
name: 'home',
data:function(){
return {
tabActive:"0",
}
}
</script>
引入tabBtn文件
//mall/src/views/Home.vue
import tabBtn from '@/components/tabBtn.vue'
把tabBar显示在页面上
//mall/src/views/Home.vue
<tab-btn></tab-btn>
设置id为category,导入tabBa
//mall/src/views/category.vue
<template>
//设置id为category
<div id="category">
// 把tabBar放进来
<tab-btn></tab-btn>
</div>
</template>
<script>
//导入tabBar
import tabBtn from '@/components/tabBtn.vue'
export default {
data(){
return {
}
},
//导入
components:{
tabBtn
}
}
</script>
to跳转到分类页面category
//mall/src/components/tabBtn.vue
<van-tabbar-item icon="home-o" to="/">首页</van-tabbar-item>
<van-tabbar-item icon="qr" to="/category">分类</van-tabbar-item>
监听路由变化,改变v-model的tabActive值
mounted() {
// 监听路由
switch(this.$route.path){
case "/category":
this.tabActive = 2;
break;
case '/':
this.tabActive = 0;
break;
default:
this.tabActive = 0;
}
},
3、分类选择
TreeSelect 分类选择
https://vant-contrib.gitee.io/vant/#/zh-CN/tree-select
4、ajax请求获取数据
//mall/src/views/category.vue
<template>
<div id="category">
<van-search placeholder="商品搜索 共239万款好物" input-align='center' v-model="searchData" />
<tab-btn></tab-btn>
</div>
</template>
<script>
import tabBtn from '@/components/tabBtn.vue'
import axios from 'axios'
import api from '@/assets/config/api.js'
export default {
data(){
return {
searchData:"",
}
},
async created() {
// ajax请求
let res = await axios.get(api.CatalogList)
let data = res.data;
console.log(data)
},
components:{
tabBtn
}
}
</script>
data里面的categoryList数据
还有里面的子数据subCategoryList
5、获取数组categoryList,并进行循环
//mall/src/views/category.vue
<template>
<div id="category">
<van-search placeholder="商品搜索 共239万款好物" input-align='center' v-model="searchData" /> <van-tree-select
:items="items"
:main-active-index.sync="activeIndex"
>
//子内容,九宫格
<template slot="content">
</template>
<tab-btn></tab-btn>
</div>
</template>
<script>
import tabBtn from '@/components/tabBtn.vue'
import axios from 'axios'
import api from '@/assets/config/api.js'
export default {
data(){
return {
searchData:"",
activeIndex: 0,
data:{
},
}
},
async created() {
// ajax请求
let res = await axios.get(api.CatalogList)
let data = res.data;
this.data = data.data;
},
computed: {
items:function(){
//判断ajax的data.categoryList是否undefined,是的话返回空数组,不是的话返回数组进行循环
if(this.data.categoryList==undefined){
return []
}else{
// console.log(123)
let arr = []
//对数据进行循环
this.data.categoryList.forEach((item,index)=>{
// console.log(index)
item.text = item.name
// 修改数据
arr.push(item)
})
// 返回数组arr
return arr;
}
components:{
tabBtn
}
}
6、修改分类选择的高度
//mall/src/views/category.vue
<van-tree-select
:items="items"
:main-active-index.sync="activeIndex"
//减去搜索框和标签栏高度
height='calc(100vh - 104px)'
@click-nav='changeRight'
>
7、添加点击事件@click-nav,获取回调参数index
//mall/src/views/category.vue
<van-tree-select
:items="items"
:main-active-index.sync="activeIndex"
height='calc(100vh - 104px)'
@click-nav='changeRight'
>
<script>
methods: {
//点击事件获取activeIndex索引值
changeRight:function(index){
console.log(index)
}
},
</script>
8、监听activeIndex改变,获取categoryList的id
//mall/src/views/category.vue
// 监听activeIndex改变
watch: {
activeIndex:async function(){
//判断有没有数据,没有的话返回空数组
if(this.items.length!==0){
//通过当前的id去请求数据
let id = this.items[this.activeIndex].id
console.log(id)
}else{
this.subCategoryList = []
}
}
},
watch: {
activeIndex:async function(){
//判断有没有数据,没有的话返回空数组
if(this.items.length!==0){
//通过当前的id去请求数据
let id = this.items[this.activeIndex].id
// console.log(id)
//通过id请求数据
//传参需要里面写对象params
let res = await axios.get(api.CatalogCurrent,{
params:{
id}})
console.log(res)
this.subCategoryList = res.data.data.currentCategory.subCategoryList
//获取九宫格上面的图片地址
this.bannerImg = this.data.currentCategory.img_url;
}else{
this.subCategoryList = []
}
}
},
//自定义内容,九宫格
<template slot="content">
<div class='imgbanner'>
<img width="100%" :src="bannerImg" alt="">
</div>
<van-grid :column-num="3">
<van-grid-item v-for="(item,index) in subCategoryList" :key="index" :icon="item.wap_banner_url" :text="item.name" :to="'/categoryList/'+item.id" >
</van-grid-item>
</van-grid>
</template>
1、标签页
Tab 标签页,标签栏滚动
https://vant-contrib.gitee.io/vant/#/zh-CN/tab
//mall/src/views/categorylist.vue
<template>
<div id="categoryList">
<van-tabs v-model="active">
<van-tab title="标签 1">内容 1</van-tab>
<van-tab title="标签 2">内容 2</van-tab>
<van-tab title="标签 3">内容 3</van-tab>
<van-tab title="标签 4">内容 4</van-tab>
</van-tabs>
</div>
</template>
<script>
export default {
//设定props
props:['id'],
data(){
return {
tabActive:0,
}
},
created() {
console.log(this.id)
}
}
</script>
2、在index.js设置props
//mall/src/router/index.js
import categorylist from '@/views/categorylist'
{
path:'/categorylist/:id',
name:'categorylist',
component: categorylist,
//通过props传进来,props改为true
props:true
}
**3、在main.js进行全局导入**
//mall/src/main.js
import api from '@/assets/config/api.js'
new Vue({
data:{
api:api
}
})
<script>
//mall/src/views/categorylist.vue
import axios from 'axios'
export default {
//设定props
props:['id'],
data(){
return {
tabActive:0,
}
},
created() {
console.log(this.$root.api)
}
}
</script>
然后就能得到数据
**4、获取数据**
<script>
//mall/src/views/categorylist.vue
import axios from 'axios'
export default {
//设定props
props:['id'],
data(){
return {
tabActive:0,
}
/ },
created() {
let res = await axios.get(this.$root.api.GoodsCategory,{
params:{
id:this.id}})
console.log(res.data)
}
}
</script>
<template>
<div id="categoryList">
<van-tabs v-model="tabActive">
<van-tab v-for="(item,index) in clist"
:key="index"
:title="item.name">
<h3>{
{
item.name}}</h3>
<p>{
{
item.front_name}}</p>
</van-tab>
</van-tabs>
</div>
</template>
<script>
import axios from 'axios'
export default {
//设定props
props:['id'],
data(){
return {
tabActive:0,
clist:[]
}
},
async created() {
// console.log(this.id)
// console.log(this.$root.api)
let res = await axios.get(this.$root.api.GoodsCategory,{
params:{
id:this.id}})
this.clist = res.data.data.brotherCategory
console.log(res.data)
},
}
</script>
async created() {
//ajax请求
let res = await axios.get(this.$root.api.GoodsCategory,{
params:{
id:this.id}})
console.log(res.data)
this.clist = res.data.data.brotherCategory
let id = this.clist[0].id;
this.clist.forEach(async (item,index)=>{
//获取函数getlist的数据
item.plist= await this.getlist(item.id,1)
console.log(item.plist)
this.$forceUpdate()
})
},
methods: {
async getlist(cid,page){
let res = await axios.get(`${
this.$root.api.GoodsList}?categoryId=${
cid}&page=${
page}&size=20`)
console.log(res)
return res.data.data
},
},
**7、将商品列表的数据渲染在页面上**
//mall/src/views/categorylist.vue
<template>
<div id="categoryList">
//Tab 标签页
<van-tabs v-model="tabActive">
<van-tab v-for="(item,index) in clist"
:key="index"
:title="item.name">
<h3>{
{
item.name}}</h3>
<p>{
{
item.front_name}}</p>
<div v-if="item.plist">
//九宫格
<van-grid :border="true" :column-num="2">
<van-grid-item v-for="(item1,index1) in item.plist.data" :to="'/product/'+item1.id" :key="index1">
<van-image
width="100"
height="100"
:src="item1.list_pic_url"
/>
<h4 class="van-ellipsis">{
{
item1.name}}</h4>
<p class="price">¥{
{
item1.retail_price}}</p>
</van-grid-item>
</van-grid>
</div>
</van-tab>
</van-tabs>
</div>
</template>
<script>
import axios from 'axios'
export default {
//设定props
props:['id'],
data(){
return {
tabActive:0,
clist:[]
}
},
async created() {
//ajax请求
let res = await axios.get(this.$root.api.GoodsCategory,{
params:{
id:this.id}})
console.log(res.data)
this.clist = res.data.data.brotherCategory
let id = this.clist[0].id;
this.clist.forEach(async (item,index)=>{
//获取函数getlist的数据
item.plist= await this.getlist(item.id,1)
console.log(item.plist)
this.$forceUpdate()
})
},
methods: {
async getlist(cid,page){
let res = await axios.get(`${
this.$root.api.GoodsList}?categoryId=${
cid}&page=${
page}&size=20`)
console.log(res)
return res.data.data
},
},
}
</script>
<style lang="less">
#categoryList{
.van-ellipsis{
width: 100%;
font-size: 14px;
font-weight: 500;
padding: 0 10px;
}
.van-grid-item{
overflow: hidden;
box-sizing: border-box;
}
.price{
color:red;
}
}
</style>
1、新建页面
在mall/src/views新建一个页面product.vue
//mall/src/views/product.vue
<template>
<div>
<h1>product</h1>
</div>
</template>
在categorylist.vue ,设置路由入口to
//mall/src/views/categorylist.vue
<van-grid-item v-for="(item1,index1) in item.plist.data" :to="'/product/'+item1.id" :key="index1">
2、NavBar 导航栏
https://vant-contrib.gitee.io/vant/#/zh-CN/nav-bar
van-nav-bar
title="商品"
left-text="返回"
left-arrow
@click-left="onClickLeft"
/>
methods:{
onClickLeft:function(){
this.$router.go(-1);
},
3、轮播
<van-swipe :autoplay="3000">
<van-swipe-item v-for="(image, index) in images" :key="index">
<img class="swipeImg" v-lazy="image.img_url" />
</van-swipe-item>
</van-swipe>
computed:{
images:function(){
if(this.data.gallery==undefined){
return []
}else{
return this.data.gallery;
}
}
},
export default {
props:['id'],
data() {
return {
data:{
},
}
async created(){
this.$store.dispatch('AjaxCart');
let res = await axios.get(this.$root.api.GoodsDetail,{
params:{
id:this.id}})
console.log(res.data)
this.data = res.data.data;
}
}
.swipeImg{
width: 100%;
}
<div class='info'>
<span>30天无忧退货</span>
<span>48小时快速退款</span>
<span>满88元免邮费</span>
</div>
.info{
display: flex;
justify-content: space-around;
font-size: 12px;
color: #999;
height: 24px;
line-height: 24px;
background: #efefef;
span{
position: relative;
}
span::before{
content:"";
display: block;
position: absolute;
left: -10px;
top: 8px;
width: 4px;
height: 4px;
border-radius: 2px;
border: 1px solid red;
}
5、商品参数
<van-cell title="请选择规格数量" is-link />
<div class="proParams">
<h3>商品参数</h3>
<div class="proItem" v-for="(item1,index1) in attribute" :key="index1">
<span class="title">{
{
item1.name}}</span>
<span class="value">{
{
item1.value}}</span>
</div>
</div>
async created(){
this.attribute = this.data.attribute;
}
.van-cell__title{
text-align: left;
}
.proItem{
width: 90%;
margin: 0 auto;
display: flex;
justify-content: space-between;
height: 24px;
color: #999;
font-size: 12px;
background: #efefef;
line-height: 24px;
text-align: left;
span.title{
width:45px;
padding: 0 10px;
border-right: 1px solid #ccc;
}
span.value{
width: 260px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
//引入html
<div class="proDetail" v-html="info.goods_desc">
</div>
.proDetail{
width: 100%;
img{
width: 100%
}
p{
margin: 0;
padding: 0;
display: flex;
}
}
1、GoodsAction 商品导航
https://vant-contrib.gitee.io/vant/#/zh-CN/goods-action
Sku 商品规格
https://vant-contrib.gitee.io/vant/#/zh-CN/sku
2、修改加入购物车时的商品规格sku
//商品导航
<van-goods-action>
<van-goods-action-icon to="/buycart" :info="$store.state.cartTotal.goodsCount==0?'':$store.state.cartTotal.goodsCount" icon="cart-o" text="购物车" />
<van-goods-action-icon icon="star-o" text="已收藏" />
<van-goods-action-button @click="chooseSku" type="warning" text="加入购物车" />
<van-goods-action-button type="danger" text="立即购买" />
</van-goods-action>
//选择商品规格
<<van-sku
v-model="showSku"
:sku="sku"
:goods="goods"
@buy-clicked="onBuyClicked"
@add-cart="onAddCartClicked"
/>
</div>
export default {
props:['id'],
data(){
return {
data:{
},
info:{
},
attribute:[],
showSku:false,
sku:sku,
goods: {
// 商品标题
title: '测试商品',
// 默认商品 sku 缩略图
picture: 'https://img.yzcdn.cn/1.jpg'
}
}
let sku = {
// 所有sku规格类目与其值的从属关系,比如商品有颜色和尺码两大类规格,颜色下面又有红色和蓝色两个规格值。
// 可以理解为一个商品可以有多个规格类目,一个规格类目下可以有多个规格值。
tree: [
{
k: '颜色', // skuKeyName:规格类目名称
v: [
{
id: '30349', // skuValueId:规格值 id
name: '红色', // skuValueName:规格值名称
},
{
id: '1215',
name: '蓝色',
}
],
k_s: 's1' // skuKeyStr:sku 组合列表(下方 list)中当前类目对应的 key 值,value 值会是从属于当前类目的一个规格值 id
}
],
// 所有 sku 的组合列表,比如红色、M 码为一个 sku 组合,红色、S 码为另一个组合
list: [
{
id: 2259, // skuId,下单时后端需要
price: 100, // 价格(单位分)
's-1': '2', // 规格类目 k_s 为 s1 的对应规格值 id
's-2': '3', // 规格类目 k_s 为 s2 的对应规格值 id
stock_num: 110 // 当前 sku 组合对应的库存
},
{
id: 2259, // skuId,下单时后端需要
price: 100, // 价格(单位分)
's-1': '1', // 规格类目 k_s 为 s1 的对应规格值 id
's-2': '4', // 规格类目 k_s 为 s2 的对应规格值 id
stock_num: 130 // 当前 sku 组合对应的库存
}
],
price: '1.00', // 默认价格(单位元)
stock_num: 227, // 商品总库存
}
}
添加点击事件,控制商品规格的显示,showSku为true弹出,,showSku为flase收起
methods:{
//商品规格按钮
onBuyClicked:function(){
// 将当前的内容提交到订单页
this.showSku = false;
},
//购物车按钮
chooseSku(){
this.showSku = true;
}
把数据库数据商品图片和价格放进去sku里面
async created(){
//把商品图片名字从数据放在页面上
this.goods.picture = this.info.primary_pic_url;
this.goods.title = this.info.name;
//修改价格
this.sku.price = this.info.retail_price;
//修改剩余数
this.sku.stock_num = this.info.goods_number;
}
从specificationList拿到数据后,进行循环再赋值给sku(其他商品specificationList可能是空,这会导致sku无效,) 下图的商品specificationList有数据
async created(){
this.$store.dispatch('AjaxCart');
let res = await axios.get(this.$root.api.GoodsDetail,{
params:{
id:this.id}})
console.log(res.data)
this.data = res.data.data;
this.info = this.data.info;
this.attribute = this.data.attribute;
this.goods.picture = this.info.primary_pic_url;
this.goods.title = this.info.name;
this.sku.price = this.info.retail_price;
this.sku.stock_num = this.info.goods_number;
//将数据进行循环
let tree = []
this.data.specificationList.forEach((item,index)=>{
let arr = []
item.valueList.forEach((product,i)=>{
arr.push({
id: product.id, // skuValueId:规格值 id
name: product.value, // skuValueName:规格值名称
})
})
// 把数据放到sku里面
tree.push({
k: item.name, // skuKeyName:规格类目名称
v: arr,
k_s: "s-"+item.specification_id // skuKeyStr:sku 组合列表(下方 list)中当前类目对应的 key 值,value 值会是从属于当前类目的一个规格值 id
})
})
this.sku.tree = tree;
}
}
然后再添加list数组,不然商品规格无法选取,变成灰色
let sku ={
list: [
{
id: 2259, // skuId
s1: '1', // 规格类目 k_s 为 s1 的对应规格值 id
s2: '1', // 规格类目 k_s 为 s2 的对应规格值 id
price: 100, // 价格(单位分)
stock_num: 110 // 当前 sku 组合对应的库存
},
{
id: 2259, // skuId
's-1': '2', // 规格类目 k_s 为 s1 的对应规格值 id
's-2': '3', // 规格类目 k_s 为 s2 的对应规格值 id
price: 110, // 价格(单位分)
stock_num: 110 // 当前 sku 组合对应的库存
},
{
id: 2259, // skuId
's-1': '1', // 规格类目 k_s 为 s1 的对应规格值 id
's-2': '4', // 规格类目 k_s 为 s2 的对应规格值 id
price: 110, // 价格(单位分)
stock_num: 130 // 当前 sku 组合对应的库存
}
],
}
3、把商品数据放进购物车
点击事件获取回调函数,获取商品规格
onAddCartClicked(skuData){
console.log(skuData)
}
onAddCartClicked(skuData){
this.showSku = false;
// console.log(skuData)
let chooseContent = skuData.selectedSkuComb['s-1']+'_'+skuData.selectedSkuComb['s-2']
console.log(chooseContent)
let resultPro = this.data.productList.filter((item,index)=>{
//判断选择的内容是否等于服务器内容。
if(item.goods_specification_ids==chooseContent){
return true
}else{
return false
}
})
console.log(resultPro)
},
加入购物车的数量selectedNum
把商品规格数据通过ajax发到后端(如果用户发送数据,会显示用户的特定值)
let cartRes = await axios.post(this.$root.api.CartAdd,{
goodsId:resultPro[0].goods_id , number: skuData.selectedNum, productId: resultPro[0].id })
apj接口
let cartRes = await axios.post(this.$root.api.CartAdd,{
goodsId:resultPro[0].goods_id , number: skuData.selectedNum, productId: resultPro[0].id })
let data = cartRes.data.data
console.log(cartRes.data)
商品的数量,总价格
//mall/scr/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import api from '@/assets/config/api.js'
import axios from 'axios'
export default new Vuex.Store({
state: {
cartTotal:{
goodsCount: 0,
goodsAmount: 0,
checkedGoodsCount: 0,
checkedGoodsAmount: 0
},
cartList:[],
},
mutations: {
setCarList:function(state,cartList){
state.cartList = cartList
},
setCartTotal:function(state,cartTotal){
state.cartTotal = cartTotal
}
},
actions: {
AjaxCart:async function(content){
let cartRes = await axios.get(api.CartList)
// console.log(cartRes.data)
content.commit('setCarList',cartRes.data.data.cartList)
content.commit('setCartTotal',cartRes.data.data.cartTotal)
}
},
modules: {
}
})
//三元运算
<van-goods-action-icon :info="$store.state.cartTotal.goodsCount==0?'':$store.state.cartTotal.goodsCount" icon="cart-o" text="购物车" />
export default {
methods:{
async onAddCartClicked(skuData){
// 修改提交
let data = cartRes.data.data
this.$store.commit('setCarList',data.cartList),
this.$store.commit('setCartTotal',data.cartTotal)
}
async created(){
// 调用mall/scr/store/index.js的AjaxCart
this.$store.dispatch('AjaxCart');
}
}
这是点击加入购物车,选择商品规格,这样就能将总商品数显示在购物车上
1、新建购物车页面
//mall/src//views/buycart.vue
<template>
<div id="buycart">
<div class='info'>
<span>30天无忧退货</span>
<span>48小时快速退款</span>
<span>满88元免邮费</span>
</div>
</div>
</template>
style lang="less">
//mall/src//views/product.vue
#buycart{
.info{
display: flex;
justify-content: space-around;
font-size: 12px;
color: #999;
height: 24px;
line-height: 24px;
background: #efefef;
span{
position: relative;
}
span::before{
content:"";
display: block;
position: absolute;
left: -10px;
top: 8px;
width: 4px;
height: 4px;
border-radius: 2px;
border: 1px solid red;
}
}
}
</style>
在product.vue页面商品导航加上进入购物车页面的入口
//mall/src//views/product.vue
<van-goods-action-icon to="/buycart" :info="$store.state.cartTotal.goodsCount==0?'':$store.state.cartTotal.goodsCount" icon="cart-o" text="购物车" />
设置路由
//mall/src/router/index.js
import buycart from '@/views/buycart'
{
path:"/buycart",
name:"buycart",
component:buycart
}
2、获取购物车的商品规格数据
//mall/src//views/buycart.vue
//导入//mall/scr/store/index.js数据
import {
mapState} from 'vuex';
import axios from 'axios'
//导入mall/scr/store/index.js里面的'cartTotal','cartList'
let mapStateObj = mapState(['cartTotal','cartList'])
export default {
data(){
return {
}
},
computed:{
//解析构造
...mapStateObj,
},
created(){
//获取mall/scr/store/index.js里面的'AjaxCart'数据
this.$store.dispatch('AjaxCart')
},
mounted(){
//输出mall/scr/store/index.js的cartList
console.log(this.cartList)
},
}
输出this.cartList(点击购物车才会出来,刷新页面没有反应)
3、列表
Card 卡片 https://vant-contrib.gitee.io/vant/#/zh-CN/card
Checkbox 复选框
https://vant-contrib.gitee.io/vant/#/zh-CN/checkbox
把cartList的数据渲染到页面上
<div class="list">
<div class="cartItem" v-for="(item,index) in cartList" :key="index">
// 复选框
<van-checkbox v-model="item.checked"></van-checkbox>
//fit='cover'填充模式
<van-image
fit='cover'
width="70"
height="70"
:src="item.list_pic_url"
/>
<div class="proBrief">
<div class="title">
<span>{
{
item.goods_name}}</span>
<span class="num">X{
{
item.number}}</span>
</div>
<p class="brief">{
{
item.goods_specifition_name_value}}</p>
<p class="price">¥ {
{
item.retail_price}}</p>
</div>
</div>
</div>
<style lang="less">
#buycart{
.info{
display: flex;
justify-content: space-around;
font-size: 12px;
color: #999;
height: 24px;
line-height: 24px;
background: #efefef;
span{
position: relative;
}
span::before{
content:"";
display: block;
position: absolute;
left: -10px;
top: 8px;
width: 4px;
height: 4px;
border-radius: 2px;
border: 1px solid red;
}
}
.cartItem{
padding: 0 5px;
display: flex;
align-items: center;
padding: 10px 5px;
.van-checkbox{
margin: 0 5px;
}
.van-image{
background: #efefef;
}
.proBrief{
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
height: 70px;
padding: 0 10px;
.title{
width: 100%;
font-size: 14px;
display: flex;
justify-content: space-between;
}
.brief{
color: #999;
font-size: 12px;
}
}
}
}
</style>
把数据渲染到提交订单上
<van-submit-bar
:price="cartTotal.checkedGoodsAmount*100"
button-text="提交订单"
@submit="onSubmit"
>
<van-checkbox v-model="checkedAll">全选</van-checkbox>
</van-submit-bar>
SubmitBar 提交订单栏
https://vant-contrib.gitee.io/vant/#/zh-CN/submit-bar
<van-checkbox v-model="checkedAll">全选</van-checkbox>
computed:{
checkedAll:{
set(val){
console.log(val,'设置全选')
},
get(){
//选中的数量goodsCount是否==checkedGoodsCount
if(this.cartTotal.goodsCount==this.cartTotal.checkedGoodsCount){
return true;
}else{
return false;
}
}
},
...mapStateObj,
},
给复选框添加点击事件
<van-checkbox @change="checkEvent($event)" v-model="item.checked"></van-checkbox>
checkEvent:async function(event){
console.log(event)
}
<van-checkbox @change="checkEvent($event,item)" v-model="item.checked"></van-checkbox>
checkEvent:async function(event,item){
console.log(event)
console.log(item)
}
输出item,其中checked为true,表示选中
修改发送并储存isChecked,productIds值。isChecked改为1或者0
checkEvent:async function(event,item){
// console.log(event)
// console.log(item)
let res = await axios.post(this.$root.api.CartChecked,{
isChecked: Number(event),productIds: item.product_id})
let data = res.data.data
console.log(data)
this.$store.commit('setCarList',data.cartList),
this.$store.commit('setCartTotal',data.cartTotal)
}
这样页面刷新复选框的选择也不会改变