vue 项目之购物流程
首页商品展示
- 使用宫格组件,实现首页商品的两列展示
https://vant-contrib.gitee.io/vant/#/zh-CN/grid
- 属性介绍
column-num
展示的列数@click="gotoDetails(value._id)"
点击去往详情页
- 一般来说,在created钩子函数之中,获取到商品数据,因为这时候的数据是已经初始化好了
- 然后把这些数据,存储在data之中,用于列表的渲染
<template>
<div class="home">
<!-- 商品列表 -->
<van-grid class="my-goods" :column-num="2">
<van-grid-item v-for="value in goodsList" :key="value._id" @click="gotoDetails(value._id)">
<van-image class="goodsImg" :src="value.imgurl" />
<h4>{{ value.name}}</h4>
</van-grid-item>
</van-grid>
</div>
</template>
<script>
import Vue from "vue";
export default {
name: "Home",
data() {
return {
//商品列表的数据
goodsList: [],
};
},
async created() {
//商品列表的请求
const { data: goodsList } = await this.$request.get("/goods");
// console.log("我是商品列表", goodsList);
this.goodsList = goodsList;
},
methods: {
//点击 具体的商品 去往详情页!
gotoDetails(id) {
// this.$router.push("/gotoDetails/" + id);
this.$router.push({
name: "Details",
params: {
id,
},
});
},
},
};
</script>
商品详情页
- 需求:
- 详情页的展示 img
- 一进入页面的时候,拿到url中的id,发起请求,拿到当前商品的详情数据 然后数据渲染
- 点击这个img 进入图片预览模式
https://vant-contrib.gitee.io/vant/#/zh-CN/image-preview
@click="showBig"
- 点击购物车,去往购物车页面 购物车之中显示多少商品,这需要使用到vuex数据共享了!
- 点击假如购物车
- 假如购物车之中有商品了,那么就数量加1,否则的话,就是给购物车添加一个商品数据
- 先拿到当前商品的id,需要从商品数据中结构出来
- 拿着当前的id去,引用vuex中的购物车数组,查询是否有当前id
- 如果当前id存在,那么就修改当前商品的数量,否则的话,就新增一条商品数据 (这些需要
- 是否显示下面的tabbar
<!-- -->
<template>
<div class="details">
<!-- 导航栏目 -->
<van-nav-bar left-text="返回" @click-left="backHome" left-arrow></van-nav-bar>
<!-- 图书详情 -->
<div class="smallImg-box">
<van-image class="smallImg" @click="showBig" :src="goodsDetails.imgurl"></van-image>
<div class="recommend-box">
<h1>{{ goodsDetails.name}}</h1>
<h4>{{ goodsDetails.auth}}</h4>
<h5>连载中</h5>
</div>
</div>
<div class="validity-con">
<h3>内容简介</h3>
<p>{{ goodsDetails.intro }}</p>
</div>
<!-- 图书推荐 -->
<div class="recomment-box">
<h3>图书推荐</h3>
<van-grid class="my-goods" :column-num="3">
<van-grid-item
v-for="value in goodsRecomemnt"
:key="value._id"
@click="gotoDetails(value._id)"
>
<van-image class="goodsImg" :src="value.imgurl" />
<h4>{{ value.name}}</h4>
</van-grid-item>
</van-grid>
</div>
<!-- 购物车 -->
<van-goods-action>
<van-goods-action-icon icon="chat-o" text="客服" color="#07c160" />
<van-goods-action-icon :badge="cartLength" @click="gotoCart" icon="cart-o" text="购物车" />
<van-goods-action-icon icon="star" text="已收藏" color="#ff5000" />
<van-goods-action-button @click="addToCart" type="warning" text="加入购物车" />
<van-goods-action-button @click="buyNow" type="danger" text="立即购买" />
</van-goods-action>
</div>
</template>
<script>
import Vue from "vue";
import {
ImagePreview,
GoodsAction,
GoodsActionButton,
GoodsActionIcon,
NavBar,
} from "vant";
Vue.use(ImagePreview);
Vue.use(GoodsAction);
Vue.use(GoodsActionButton);
Vue.use(GoodsActionIcon);
Vue.use(NavBar);
export default {
name: "GotoDetails",
data() {
return {
goodsDetails: [],
goodsRecomemnt: [],
};
},
created() {
const id = this.$route.params.id;
this.getDetail(id);
this.getRecomment();
},
computed: {
cartLength() {
return this.$store.state.cartList.length;
},
},
methods: {
//点击返回首页
backHome() {
this.$router.push({
name: "Home",
});
},
// 获取详情页的数据
async getDetail(id) {
//拿着id 发起请求 拿到详情页的数据
const {
data: {
data: { result: goods },
},
} = await this.$request.get("/goods/" + id);
// console.log("我是详情页111", goods[0]);
this.goodsDetails = goods[0];
},
// 显示大图片
showBig() {
//图片传入到数组之中
ImagePreview([this.goodsDetails.imgurl]);
},
// 获取推荐页的数据
async getRecomment() {
const { data } = await this.$request.get("/goods");
// console.log("我是推荐的", data);
this.goodsRecomemnt = data;
},
//跳转到 详情页
gotoDetails(id) {
// console.log("我是跳转的id", id);
this.$router.push({
name: "Details",
params: {
id,
},
});
},
//去往购物车
gotoCart() {
this.$router.push({
name: "Cart",
});
},
//加入购物车
addToCart() {
//判断购物车里面是否有这个商品 有的话 数量+1 没有的话 就qty为1
const { _id: id } = this.goodsDetails; //拿到当前商品的id
//根据id 去查询购物车 里面是否含有该id的商品!
const current = this.$store.state.cartList.filter(
(item) => item._id === id
)[0];
// console.log("我是当前的", current); // 如果有的话 那么qty++ 没有的话添加商品!
if (current) {
this.$store.dispatch("changeQtyAsunc", { id, qty: current.qty + 1 });
} else {
const goods = {
...this.goodsDetails,
qty: 1,
};
// 调用mutation 中的addToCart方法
// this.$store.commit("addToCart", goods);
this.$store.dispatch("addToCart", goods);
}
},
//立即购买
buyNow() {
this.addToCart();
//跳转到购物车
this.$router.push({
name: "Cart",
});
},
},
beforeRouteUpdate(to, from, next) {
console.log(to.params.id, from.params.id);
if (to.params.id !== from.params.id) {
// console.log("我是去的id", to.params.id);
this.getDetail(to.params.id);
this.getRecomment();
}
next();
},
mounted() {
//触发销毁事件
this.$store.commit("isShowMenu", false);
},
destroyed() {
//触发销毁事件
this.$store.commit("isShowMenu", true);
}
};
</script>
vuex中的数据
这是在vuex数据,缺少操作数据库的步骤
import Vue from 'vue'
import Vuex from 'vuex'
import $request from "../network/request"
import {
Notify
} from 'vant';
Vue.use(Vuex)
export default new Vuex.Store({
state: {
//是否显示那个tabbar
isShowMemu: true,
totalPrice: "", //总价
//购物车的数据
cartList: [{
"_id": "5f4f5e38aaf12252fb74c93b",
"name": "鼎定乾坤",
"date": "2020 08-19 11:28",
"intro": "玄黄缔造者……极致超脱之路,哪怕天难葬其身,地难灭其魂。亦难以跳出那个圈。星空崩塌,万族凋零。如何以一己之力逆转乾坤,颠倒阴阳。且看那一袭青衫,一柄长剑,一方圆鼎:脚踏修真,拳碎仙域,剑斩神界,鼎定至尊,极致超脱。书群,1141419286扣扣",
"auth": "浅山深水",
"imgurl": "imgbook1/f3aa24ea917f79a95b81ea86c91b4043.jpeg",
"price": 123.2,
"qty": 1,
"check": false
}, {
"_id": "5f4f5e38aaf12252fb74c93e",
"name": "雷神传之雷神再世",
"date": "2020 08-18 22:47",
"intro": "以武侠小说的名义 ,说一段刻骨铭心的爱情故事 !",
"auth": "猛士七",
"imgurl": "imgbook1/ba83c1528c275b6c154ffd482d4541c3.jpeg",
"price": 12,
"qty": 1,
"check": false
}]
},
getters: {
//计算总价
totalPrice(state) {
return state.cartList.reduce((pre, cue) => pre + cue.price * cue.qty, 0) * 100
},
},
mutations: {
//显示
isShowMenu(state, payload) {
// console.log("我是mutations", payload);
state.isShowMemu = payload
},
//修改购物车数量
changeQty(state, payload) {
console.log("mu修改数量", payload);
state.cartList = state.cartList.map(item => {
if (item._id === payload.id) {
item.qty = payload.qty
}
return item
})
},
// 添加购物车
addToCart(state, payload) {
// console.log("我是添加购物车", payload);
state.cartList.unshift(payload)
},
//删除购物车 item
delGoods(state, payload) {
// console.log("我是删除的item", payload);
state.cartList = state.cartList.filter(item => item._id !== payload)
},
//清空购物车
clearCart(state) {
console.log("我是清空触发");
state.cartList = []
}
},
actions: {
//请求 查询库存多少! /:id/kucun
async changeQtyAsunc(context, payload) {
const {
data
} = await $request.get(`/goods/${payload.id}/kucun`)
if (payload.qty > data.kucun) {
Notify({
type: 'danger',
message: '超过库存,仅能下单这些!'
});
payload.qty = data.kucun
}
// console.log("我是修改后的", payload);
context.commit("changeQty", payload)
},
// async getCart() {
// console.log("我被调用了!");
// const data = await $request.get(`/goods/:cart`)
// console.log("我是获取购物车列表", data);
// }
},
modules: {}
})
这是一个添加商品的数据
import request from "../newwork/request"
const bookCategory = {
state: {
shelfList: [],
totalPrice: "",
},
getters: {
totalPrice(state) {
return state.cartList.reduce((pre, cue) => pre + cue.price * cue.qty, 0) * 100
},
},
mutations: {
isShowMenu(state, payload) {
state.isShowMemu = payload
},
async getShelfList(state) {
const {
data: getShelf
} = await request.get("/shelf");
state.shelfList = getShelf.data;
},
async joinShelf(state, payload) {
const {
bookid
} = payload
const {
data: joinShelfList
} = await request.get(`/shelf/repeat/${bookid}`);
if (joinShelfList.code === 0) {
await request.post("/shelf", {
...payload
});
}
}
},
actions: {
joinShelf(context, payload) {
return new Promise((resolve) => {
context.commit("joinShelf", payload)
resolve("添加成功")
})
},
}
}
export default bookCategory;
import Vue from 'vue'
import Vuex from 'vuex'
import $request from "../network/request"
import {
Notify
} from 'vant';
Vue.use(Vuex)
export default new Vuex.Store({
state: {
isShowMemu: true,
totalPrice: "",
cartList: [{
"_id": "5f4f5e38aaf12252fb74c93b",
"name": "鼎定乾坤",
"date": "2020 08-19 11:28",
"intro": "玄黄缔造者……极致超脱之路,哪怕天难葬其身,地难灭其魂。亦难以跳出那个圈。星空崩塌,万族凋零。如何以一己之力逆转乾坤,颠倒阴阳。且看那一袭青衫,一柄长剑,一方圆鼎:脚踏修真,拳碎仙域,剑斩神界,鼎定至尊,极致超脱。书群,1141419286扣扣",
"auth": "浅山深水",
"imgurl": "imgbook1/f3aa24ea917f79a95b81ea86c91b4043.jpeg",
"price": 123.2,
"qty": 1,
"check": false
}, {
"_id": "5f4f5e38aaf12252fb74c93e",
"name": "雷神传之雷神再世",
"date": "2020 08-18 22:47",
"intro": "以武侠小说的名义 ,说一段刻骨铭心的爱情故事 !",
"auth": "猛士七",
"imgurl": "imgbook1/ba83c1528c275b6c154ffd482d4541c3.jpeg",
"price": 12,
"qty": 1,
"check": false
}]
},
getters: {
totalPrice(state) {
return state.cartList.reduce((pre, cue) => pre + cue.price * cue.qty, 0) * 100
},
},
mutations: {
isShowMenu(state, payload) {
state.isShowMemu = payload
},
changeQty(state, payload) {
console.log("mu修改数量", payload);
state.cartList = state.cartList.map(item => {
if (item._id === payload.id) {
item.qty = payload.qty
}
return item
})
},
addToCart(state, payload) {
state.cartList.unshift(payload)
},
delGoods(state, payload) {
state.cartList = state.cartList.filter(item => item._id !== payload)
},
clearCart(state) {
console.log("我是清空触发");
state.cartList = []
}
},
actions: {
async changeQtyAsunc(context, payload) {
const {
data
} = await $request.get(`/goods/${payload.id}/kucun`)
if (payload.qty > data.kucun) {
Notify({
type: 'danger',
message: '超过库存,仅能下单这些!'
});
payload.qty = data.kucun
}
context.commit("changeQty", payload)
},
},
modules: {}
})