Pinia状态管理库-数据状态同步
pinia状态管理库
在 Vue.js 中,Pinia 是一种状态管理库,它使用了响应式的数据流。当使用 Pinia 管理的数据发生变化时,与 Vue 2.x 中的 Vuex 类似,Pinia 也会触发组件的重新渲染,以确保 UI 反映最新的数据状态。
当你在 Pinia 存储中使用 ref 或 reactive 定义的数据发生变化时,相关的组件会在下一个事件循环周期内更新,这是 Vue.js 的响应式系统的一部分。这种自动的响应式更新机制使得你不需要手动调度组件的重新渲染,Vue.js 会负责处理这些变化。
cartStore.js的封装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import { defineStore } from "pinia"; export const useCartStore = defineStore({ id: 'cart', state: () => ({ cartList: [] }), actions: { addCart(goods) { const item = this.cartList.find((item) => goods.skuId === item.skuId) if (item) { item.count = item.count + goods.count } else { this.cartList.push(goods) } }, delCart(skuId) { const idx = this.cartList.findIndex((item) => skuId === item.skuId) this.cartList.splice(idx, 1) } }, getters: { allcount: (state) => { return state.cartList.reduce((a, c) => a + c.count, 0) }, allprice: (state) => { return state.cartList.reduce((a, c) => a + c.price * c.count, 0) } } })
|
当 addCart 方法修改 cartList 数据时,相关的组件将在下一个事件循环周期内进行更新,以反映 cartList 的最新状态。
总的来说,Pinia 提供了一种方便而强大的方式来管理 Vue.js 应用程序的状态,并通过其响应式系统确保数据的一致性和更新。
购物车复选框状态同步到pinia中store对应的状态
v-model双向绑定指令不方便进行命令式的操作(因为后续还需要调用接口),所以把v-model回退到一般模式,也就是:model-value和@click的配合实现。
单选框绑定一个回调函数(@change事件),并将当前的数据项数据i和单选框选中状态传递给这个回调函数。
1 2 3 4 5 6 7 8 9 10 11
| <!-- 全选框 --> <el-checkbox :model-value="useStore.isAll" @change="allCheck" />
<tr v-for="i in cartList" :key="i.id"> <td> <el-checkbox :model-value="i.selected" @change="(selected) => singleCheck(i, selected)" /> </td>
|
回调函数处理逻辑:
1、导入Pinia 状态管理库定义的购物车状态管理模块(这个模块包含了购物车的状态属性、操作方法和计算属性,允许我们在当前文件中访问和操作购物车的状态信息);
2、调用 useCartStore 函数,创建了一个名为 useStore 的 Pinia store 实例。这个实例用于在当前组件中访问购物车的状态和操作;
3、从 useStore 实例中获取购物车列表数据,将其赋值给名为 cartList 的变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <script setup> import { useCartStore } from "@/stores/cartStore"; const useStore = useCartStore(); const cartList = useStore.cartList;
const singleCheck = (i, selected) => { useStore.singleCheck(i.skuId, selected); };
const allCheck = (selected) => { console.log("点击了", selected); useStore.allcheck(selected); }; </script>
|
使用pinia状态管理库提供的 defineStore 函数定义了一个名为 useCartStore 的状态管理模块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import { defineStore } from "pinia"; export const useCartStore = defineStore({ id: 'cart', state: () => ({ cartList: [] }), actions: { addCart(goods) { const item = this.cartList.find((item) => goods.skuId === item.skuId) if (item) { item.count = item.count + goods.count } else { this.cartList.push(goods) } }, delCart(skuId) { const idx = this.cartList.findIndex((item) => skuId === item.skuId) this.cartList.splice(idx, 1) }, singleCheck(skuId, selected) { const item = this.cartList.find((item) => item.skuId === skuId) item.selected = selected }, allcheck(selected) { this.cartList.forEach((item) => item.selected = selected); } }, getters: { allcount: (state) => { return state.cartList.reduce((a, c) => a + c.count, 0) }, allprice: (state) => { return state.cartList.reduce((a, c) => a + c.price * c.count, 0) }, isAll: (state) => { return state.cartList.every((item) => { return item.selected }) } } })
|
补充:已选中数量和已选中总价格如何显示?
增加两个计算属性:
1 2 3 4 5 6 7 8 9 10 11
| selectedCount: (state) => { const selectedItems = state.cartList.filter((item) => item.selected) return selectedItems.reduce((a, c) => a + c.count, 0) }, selectedPrice: (state) => { const selectedItems = state.cartList.filter((item) => item.selected) const allprice = selectedItems.reduce((a, c) => a + c.price * c.count, 0) return allprice.toFixed(2) }
|
接口购物车
加入购物车
判断用户是否登录(看是否存在token)
如果已经登录,就调用加入购物车的接口;
然后调用获取购物车列表接口,紧接着接口购物车列表覆盖本地购物车列表。
修改相应store的actions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| async addCart(goods) { const { skuId, count } = goods if (this.isLogin) { await insertCartAPI({ skuId, count }) const res = await findNewCartListAPI() console.log('购物车列表:', res); this.cartList = res.result } else { const item = this.cartList.find((item) => goods.skuId === item.skuId) if (item) { item.count = item.count + goods.count } else { this.cartList.push(goods) } } },
|
api封装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| export const insertCartAPI = ({ skuId, count }) => { return request({ url: '/member/cart', method: 'POST', data: { skuId, count } }) }
export const findNewCartListAPI = () => { return request({ url: '/member/cart' }) }
|
删除购物车数据
逻辑和加入一样,只是接口调用不同
增加删除接口函数
1 2 3 4 5 6 7 8 9 10
| export const delCartAPI = (ids) => { return request({ url: '/member/cart', method: 'DELETE', data: { ids } }) }
|
修改对应pinia的store的actions中的删除方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| async delCart(skuId) { if (this.isLogin) { await delCartAPI([skuId]) const res = await findNewCartListAPI() console.log('购物车列表:', res); this.cartList = res.result } else { const idx = this.cartList.findIndex((item) => skuId === item.skuId) this.cartList.splice(idx, 1) }
},
|
退出登录-清空购物车数据
在购物车store中增加清空购物车的action,
组件调用store中的清空action,执行清除业务;
找到退出登录的业务逻辑,调用清除函数:
1 2 3 4 5
| clearUserInfo() { this.userInfo = {} }
|
增加清除购物车业务:
1 2 3 4 5 6 7 8
| clearUserInfo() { this.userInfo = {} const userStore = useCartStore() userStore.clearCart() } },
|
登录-更新购物车列表数据
封装一下更新购物车数据的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| async updateCart() { const res = await findNewCartListAPI() console.log('购物车列表:', res); this.cartList = res.result }, async addCart(goods) { const { skuId, count } = goods if (this.isLogin) { await insertCartAPI({ skuId, count }) this.updateCart() } else { const item = this.cartList.find((item) => goods.skuId === item.skuId) if (item) { item.count = item.count + goods.count } else { this.cartList.push(goods) } }
},
|
登录业务调用函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const doLogin = () => { const { account, password } = form.value; formRef.value.validate(async (vaild) => { console.log(vaild); if (vaild) { await userStore.getUserInfo({ account, password }); ElMessage({ type: "success", message: "登录成功" }); router.replace({ path: "/" }); const cartStore = useCartStore(); cartStore.updateCart(); } }); };
|
本地购物车和服务端购物车数据合并
为了不丢失用户在没有登录状态下的本地购物车数据,在做登录操作的时候实现一个优化,将本地购物车数据和服务端购物车数据进行一个合并。
封装合并的接口函数:其中data是数组对象,需要参数为{skuId,selected,count}
1 2 3 4 5 6 7 8
| export const mergeCartAPI = (data) => { return request({ url: '/member/cart/merge', method: 'POST', data }) }
|
在用户登录操作增加购物车合并操作,并刷新购物车列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| async getUserInfo({ account, password }) { try { const res = await loginAPI({ account, password }) console.log('用户数据:', res); this.userInfo = res.result const cartStore = useCartStore() await mergeCartAPI(cartStore.cartList.map((item) => { return { skuId: item.skuId, selected: item.selected, count: item.count } })) cartStore.updateCart(); } catch (e) { console.log('获取用户数据出错', e); } },
|
生成订单
1、调用接口生成订单id,并且携带id跳转到支付页
2、调用更新购物车列表接口,更新购物车状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const createOrder = async () => { const res = await createOrderAPI({ deliveryTimeType: 1, payType: 1, payChannel: 1, buyerMessage: "", goods: checkInfo.value.goods.map((item) => { return { skuId: item.skuId, count: item.count, }; }), addressId: defaultAddress.value.id, }); const orderId = res.result.id; router.push({ path: "/pay", query: { id: orderId, }, }); cartStore.updateCart(); };
|
接口:
1 2 3 4 5 6 7 8
| export const createOrderAPI = (data) => { return request({ url: '/member/order', method: 'POST', data }) }
|