购物车
刀刀
1/2/2025
0 字
0 分钟
思路
购物车模块分为未登录本地购物车和登录状态接口获取的购物车。
未登录状态下,数据将保存到本地存储中,在本地做增删改查操作。
登录状态下,数据通过接口动态获取,增删改查操作都调用接口向服务器发起请求。
在未登录状态下增加的数据登录后会调用接口合并购物车数据。
未登录状态
未登录状态下做的增删改查操作都是直接修改本地的数据,因此只需要通过数组内置的 map()
、filter()
、find()
等方法实现即可。
由于购物车数据多个页面都需要使用,因此放在 pinia
内做状态管理存储是不错的选择。代码如下所示:
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const useCarttStore = defineStore('cart', () => {
const cartList = ref([]) // 购物车列表数据
// 购物车商品总数数据计算
const cartCount = computed(() => cartList.value.length ? cartList.value.reduce((pre, next) => pre + next.count, 0) : 0)
return { cartList, cartCount }
}, {
persist: true
})
通过 pinia
插件设置 persist
实现本地存储,刷新后数据依旧存在。
pinia
中 state
状态数据通过 ref
创建,getter
计算数据则通过 computed
计算属性获取。最后通过 return
导出,.vue
组件按需导入使用,代码如下:
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCarttStore = defineStore('cart', () => {
const cartList = ref([]) // 购物车列表数据
return { cartList }
}, {
persist: true
})
通过 Vue Devtools
插件查看效果,如下图所示:
增加
购物车增加数据逻辑步骤为:
- 获取新增的商品数据,如数量、唯一标识、价钱、
skuId
等 - 判断数组内是否有该商品,没有则往数组内追加,存在则数量累加
// 添加购物车操作
const addCart = async (e) => {
// 无token,本地操作
let obj = {
id: e.id,
name: e.name,
price: e.price,
count: e.count,
skuId: e.skuId,
picture: e.mainPictures[0],
attrsText: e.specsText,
selected: true
}
// 判断是否添加过:添加过:数量加一;没添加过,添加数据
const item = cartList.value.find(v => v.skuId === obj.skuId)
if (item) {
item.count += obj.count
} else {
cartList.value.push(obj)
}
}
删除
通过 filter
方法过滤掉选择的商品,把新数组赋值给 cartList
数组,获取过滤后的数据,即实现删除操作。
// 删除购物车内容
const delCart = async skuId => {
cartList.value = cartList.value.filter(item => item.skuId !== skuId)
}
修改
通过数组的 find
方法,找到选中的该项数据的 item
子选项,修改它的属性。由于 Vue3
通过代理侦听作为响应式,因此该改动也能被侦听到。
// 修改购物车的选中状态
const updateCheck = (e, i) => {
const item = cartList.value.find(item => item.skuId === i.skuId)
item.selected = e
}
登录状态
登录后后端接口会返回用户的 token
,而前面为了方便多页面使用 token
在实现登录功能的时候已经把数据保存到 pinia
中,因此这里只需要引入,判断是否存在 token
。
如果有 token
,说明已经登录了,调用接口实现功能即可。
在未登录状态下保存的数据登录后需要调用接口合并购物车,否则未登录状态下保存的数据将无意义。
退出登录后要把购物车数据清空,登录后重新调接口获取最新的数据。
点击查看代码
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { useUserStore } from './user'
import { storeToRefs } from "pinia";
import { insertCartAPI, getCartListAPI, removeCartItemAPI } from '@api/cart'
export const useCarttStore = defineStore('cart', () => {
const { userinfo } = storeToRefs(useUserStore())
const cartList = ref([]) // 购物车列表数据
// 计算token
const hasToken = computed(() => userinfo.value.token)
// 获取最新购物车数据
const getCartListFn = async () => {
const res = await getCartListAPI()
cartList.value = res.result
}
// 添加购物车操作
const addCart = async (e) => {
if (hasToken) {
// 有token,调用接口
const { skuId, count } = e
await insertCartAPI({ skuId, count })
getCartListFn()
} else {
// ...
}
}
// 购物车商品总数数据计算
const cartCount = computed(() => cartList.value.length ? cartList.value.reduce((pre, next) => pre + next.count, 0) : 0)
// ...
// 删除购物车内容
const delCart = async skuId => {
if (hasToken) {
// 登录状态,调用接口删除数据
await removeCartItemAPI(skuId)
getCartListFn()
} else {
// ...
}
}
// 清空购物车
const clearCart = () => {
cartList.value = []
}
return { cartList, addCart, delCart, cartCount, ... }
}, {
persist: true
})
无响应式BUG
在功能实现时,发现有一个情况:
- 在做新增或删除操作时,页面数据无更新
- 查看本地存储和
Vue Devtools
插件时,发现pinia
中与本地存储中数据已经是最新的了,而.vue
组件中数据还是旧数据。说明获取到的数据不是响应式的。
解决方案:通过 pinia
提供的 storeToRef
属性,把获取到的值转为响应式。
注意:该方法不能用于函数使用。