老师 购物车想要通过后端接口进行创建和展示,需要在哪些地方进行修改,可以详细讲解一下吗(因为通过vuex好像有问题,即使登录不同的用户,购物车数据是被同步的)
Cart.vue页面
<template>
<div
class="mask"
v-if="showCart && calculations.total > 0"
@click="handleCartShowChange"
/>
<div class="cart">
<div class="product" v-if="showCart && calculations.total > 0">
<div class="product__header">
<div
class="product__header__all"
@click="() => setCartItemsChecked(shopId)"
>
<span
class="product__header__icon iconfont"
v-html="calculations.allChecked ? '': ''"
>
</span>
全选
</div>
<div class="product__header__clear">
<span class="product__header__clear__btn"
@click="() => cleanCartProducts(shopId)"
>清空购物车</span>
</div>
</div>
<div
v-for="item in productList"
:key="item.id"
class="product__item"
>
<div
class="product__item__checked iconfont"
v-html="item.check ? '': ''"
@click="() => changeCartItemChecked(shopId, item.id)"
/>
<img class="product__item__img" :src="item.imgUrl" />
<div class="product__item__detail">
<h4 class="product__item__title">{{item.name}}</h4>
<p class="product__item__price">
<span class="product__item__yen">¥</span>{{item.price}}
<span class="product__item__origin">¥{{item.oldPrice}}</span>
</p>
</div>
<div class="product__number">
<span
class="product__number__minus iconfont"
@click="() => { changeCartItemInfo(shopId, item.id, item, -1) }"
></span>
<span class="product__number__value">{{item.count || 0}}</span>
<span
class="product__number__plus iconfont"
@click="() => { changeCartItemInfo(shopId, item.id, item, 1) }"
></span>
</div>
</div>
</div>
<div class="check">
<div class="check__icon">
<img
src="http://www.dell-lee.com/imgs/vue3/basket.png"
class="check__icon__img"
@click="handleCartShowChange"
/>
<div class="check__icon__tag">{{calculations.total}}</div>
</div>
<div class="check__info">
总计:<span class="check__info__price">¥ {{calculations.price}}</span>
</div>
<div class="check__btn" v-show="calculations.total > 0">
<!-- 跳转到提交订单页面 -->
<router-link :to="{path: `/orderConfirmation/${shopId}`}">
去结算
</router-link>
</div>
</div>
</div>
</template>
<script>
import { ref } from 'vue'
import { useStore } from 'vuex'
import { useRoute } from 'vue-router'
import { useCommonCartEffect } from '../../effects/cartEffects'
// 获取购物车信息逻辑
const useCartEffect = (shopId) => {
const store = useStore()
const {
productList, calculations, changeCartItemInfo
} = useCommonCartEffect(shopId)
const changeCartItemChecked = (shopId, productId) => {
store.commit('changeCartItemChecked', { shopId, productId })
}
const cleanCartProducts = (shopId) => {
store.commit('cleanCartProducts', { shopId })
}
const setCartItemsChecked = (shopId) => {
// 如果全选状态,点击按钮后取消全选,如果非全选状态,点击按钮后全部选中
const allChecked = !calculations.value.allChecked
store.commit('setCartItemsChecked', { shopId, allChecked })
}
return {
calculations, productList, cleanCartProducts, changeCartItemInfo, changeCartItemChecked, setCartItemsChecked
}
}
// 展示隐藏购物车逻辑
const toggleCartEffect = () => {
const showCart = ref(false)
const handleCartShowChange = () => {
showCart.value = !showCart.value
}
return { showCart, handleCartShowChange }
}
export default {
name: 'Cart',
setup () {
const route = useRoute()
const shopId = route.params.id
const {
calculations, productList, cleanCartProducts,
changeCartItemInfo, changeCartItemChecked, setCartItemsChecked
} = useCartEffect(shopId)
const { showCart, handleCartShowChange } = toggleCartEffect()
return {
calculations, shopId, productList, cleanCartProducts, changeCartItemInfo, changeCartItemChecked, setCartItemsChecked, showCart, handleCartShowChange
}
}
}
</script>
<style lang="scss" scoped>
@import '../../style/viriables.scss';
@import '../../style/mixins.scss';
.mask {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
background: rgba(0, 0, 0, .5);
z-index: 1;
}
.cart {
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
background: $bgColor;
}
.product {
overflow-y: scroll;
flex: 1;
background: $bgColor;
&__header {
display: flex;
line-height: .52rem;
border-bottom: .01rem solid $content-bgColor;
font-size: .14rem;
color: $content-fontcolor;
&__all {
width: .64rem;
margin-left: .18rem;
}
&__icon {
display: inline-block;
margin-right: .1rem;
vertical-align: top;
color: $btn-bgColor;
font-size: .2rem;
}
&__clear {
flex: 1;
margin-right: .16rem;
text-align: right;
&__btn {
display: inline-block;
}
}
}
&__item {
position: relative;
display: flex;
padding: .12rem 0;
margin: 0 .18rem;
border-bottom: .01rem solid $content-bgColor;
&__checked {
line-height: .5rem;
margin-right: .2rem;
color: $btn-bgColor;
font-size: .2rem;
}
&__detail {
overflow: hidden;
}
&__img {
width: .46rem;
height: .46rem;
margin-right: .16rem;
}
&__title {
margin: 0;
line-height: .2rem;
font-size: .14rem;
color: $content-fontcolor;
@include ellipsis;
}
&__price {
margin: .06rem 0 0 0;
line-height: .2rem;
font-size: .14rem;
color: $hightlight-fontColor;
}
&__yen {
font-size: .12rem;
}
&__origin {
margin-left: .06rem;
line-height: .2rem;
font-size: .12rem;
color: $light-fontColor;
text-decoration: line-through;
}
.product__number {
position: absolute;
right: 0;
bottom: .26rem;
&__minus {
position:relative;
top: .02rem;
color: $medium-fontColor;
margin-right: .05rem;
font-size: .2rem;
}
&__plus {
position:relative;
top: .02rem;
color: $btn-bgColor;
margin-left: .05rem;
font-size: .2rem;
}
&__value {
font-size: .13rem;
}
}
}
}
.check {
display: flex;
height: .49rem;
border-top: .01rem solid $content-bgColor;
line-height: .49rem;
&__icon {
position: relative;
width: .84rem;
&__img {
display: block;
margin: .12rem auto;
width: .28rem;
height: .26rem;
}
&__tag {
position: absolute;
left: .46rem;
top: .04rem;
padding: 0 .04rem;
min-width: .2rem;
height: .2rem;
line-height: .2rem;
background-color: $hightlight-fontColor;
border-radius: .1rem;
font-size: .12rem;
text-align: center;
color: $bgColor;
transform: scale(.5);
transform-origin: left center;
}
}
&__info {
flex: 1;
color: $content-fontcolor;
font-size: .12rem;
&__price {
line-height: .49rem;
color: $hightlight-fontColor;
font-size: .18rem;
}
}
&__btn {
width: .98rem;
background-color: #4FB0F9;
text-align: center;
font-size: .14rem;
a {
color: $bgColor;
text-decoration: none;
}
}
}
</style>
=================================
cartEffects.js页面
import { computed } from 'vue'
import { useStore } from 'vuex'
// 购物车相关逻辑
export const useCommonCartEffect = (shopId) => {
const store = useStore()
const cartList = store.state.cartList
const changeCartItemInfo = (shopId, productId, productInfo, num) => {
store.commit('changeCartItemInfo', {
shopId, productId, productInfo, num
})
}
const productList = computed(() => {
const productList = cartList[shopId]?.productList || {}
const notEmptyProductList = {}
for (const i in productList) {
const product = productList[i]
if (product.count > 0) {
notEmptyProductList[i] = product
}
}
return notEmptyProductList
})
const shopName = computed(() => {
const shopName = cartList[shopId]?.shopName || ''
return shopName
})
const calculations = computed(() => {
const productList = cartList[shopId]?.productList
const result = { total: 0, price: 0, allChecked: true }
if (productList) {
for (const i in productList) {
const product = productList[i]
result.total += product.count
if (product.check) {
result.price += (product.count * product.price)
}
if (product.count > 0 && !product.check) {
result.allChecked = false
}
}
}
result.price = result.price.toFixed(2)
return result
})
return { cartList, shopName, productList, calculations, changeCartItemInfo }
}
==================================
store文件夹的index.js页面
import Vuex from 'vuex'
import { post } from '../utils/request'
// 给cartList数据做持久存储
const setLocalCartList = (state) => {
const { cartList } = state
const cartListString = JSON.stringify(cartList)
localStorage.cartList = cartListString
}
const getLocalCartList = () => {
// { shopId: {shopName:'', productList:{ productId: {} }}}
try {
return JSON.parse(localStorage.cartList)
} catch (e) {
return {
cartList: {}
}
}
}
export default Vuex.createStore({
state: {
cartList: getLocalCartList(),
userId: ''
},
mutations: {
saveUserId (state, payload) {
state.userId = payload.userId
},
changeCartItemInfo (state, payload) {
const { shopId, productId, productInfo } = payload
const shopInfo = state.cartList[shopId] || {
shopName: '', productList: {}
}
let product = shopInfo.productList[productId]
if (!product) {
productInfo.count = 0
product = productInfo
}
product.count = product.count + payload.num
if (payload.num > 0) { product.check = true }
if (product.count < 0) { product.count = 0 }
shopInfo.productList[productId] = product
state.cartList[shopId] = shopInfo
console.log('cart state:', state)
console.log('userId:', state.userId, 'shopId:', shopId, 'goodsId:', product.id, 'goodsNum:', product.count, 'goodsName:', product.goodsName, 'img:', product.imgUrl)
// 加入购物车
const addCart = async () => {
try {
const result = await post('/cart/create', {
shopId: shopId,
goodsId: product.id,
goodsNum: product.count,
goodsName: product.goodsName,
img: product.imgUrl
})
if (result?.code === 1) {
console.log('添加购物车成功')
} else {
console.log('添加购物车失败')
}
} catch (e) {
console.log('请求失败')
}
}
addCart()
setLocalCartList(state)
},
changeShopName (state, payload) {
const { shopId, shopName } = payload
const shopInfo = state.cartList[shopId] || {
shopName: '', productList: {}
}
shopInfo.shopName = shopName
state.cartList[shopId] = shopInfo
setLocalCartList(state)
},
changeCartItemChecked (state, payload) {
const { shopId, productId } = payload
const product = state.cartList[shopId].productList[productId]
product.check = !product.check
setLocalCartList(state)
},
cleanCartProducts (state, payload) {
const { shopId } = payload
state.cartList[shopId].productList = {}
setLocalCartList(state)
},
setCartItemsChecked (state, payload) {
// 接收allChecked
const { shopId, allChecked } = payload
const products = state.cartList[shopId].productList
if (products) {
for (const key in products) {
const product = products[key]
// 如果allChecked值为true,将每个商品的check值设为true
if (allChecked) {
product.check = true
} else {
// 如果allChecked值为false,将每个商品的check值设为false
product.check = false
}
}
}
setLocalCartList(state)
},
clearCartData (state, shopId) {
state.cartList[shopId].productList = {}
}
}
})
正在回答 回答被采纳积分+1
同学你好,解答如下:
1、首先要说一点购物车不能直接使用后端接口进行创建和展示,正常开发中是不允许的,如果每点击增加一次都要去访问后端,那么当并发量大的时候服务器端就崩了,并且这还是访问量大的电商项目。
2、vuex不是有问题,而是项目是开发阶段,如按照正常项目来说,他们在请求的时候是要带用户的token的,这样服务端就会去区别是谁在访问了,之后后端会给到前端对应用户的数据。我们在学习的时候因为都是本地开发,并没有办法去真的区分是谁在访问,另vuex在正式开发中要优化,因为如果用户在页面中刷新,会导致vuex数据被清空,所以vuex一般来说会在某些特定的场所赋值给本地缓存进行保存数据,正是因为这样所以同学即便是在怎么换账号密码,本地依然会存在数据,所以才会导致被同步的现象发生。
祝学习愉快!
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星