用python做网站开发的课程广东省自然资源厅厅长陈光荣简历
用python做网站开发的课程,广东省自然资源厅厅长陈光荣简历,域名注册的流程是什么,手机ui设计是什么在 Vue 项目开发中#xff0c;购物车是电商类应用的核心功能之一#xff0c;涉及商品的添加、删除、数量修改、价格计算、选中状态管理等多维度操作。如果直接将这些状态分散在各个组件中#xff0c;会导致数据流转混乱、组件通信复杂#xff0c;而 Vuex#xff08;Vue 2购物车是电商类应用的核心功能之一涉及商品的添加、删除、数量修改、价格计算、选中状态管理等多维度操作。如果直接将这些状态分散在各个组件中会导致数据流转混乱、组件通信复杂而 VuexVue 2/PiniaVue 3作为专为 Vue 设计的状态管理库能完美解决这一问题。本文以 Vuex 4适配 Vue 3为例从零拆解购物车的状态管理设计让你彻底掌握 Vuex 在实战中的应用。一、核心需求梳理在设计状态管理前先明确购物车的核心功能需求避免盲目设计商品加入购物车需判断是否已存在存在则累加数量修改购物车商品数量限制最小数量为 1删除购物车中的商品切换商品的选中状态单个 / 全选实时计算选中商品的总价和总数量清空购物车持久化购物车数据刷新页面不丢失。二、Vuex 核心结构设计Vuex 的核心由State状态、Getter计算属性、Mutation同步修改、Action异步 / 复杂逻辑、Module模块拆分组成。购物车作为独立功能建议拆分为独立模块避免根模块过于臃肿。1. 目录结构规划src/ ├── store/ │ ├── index.js # 仓库入口注册模块 │ └── modules/ │ └── cart.js # 购物车模块2. 购物车模块cart.js核心实现1State定义购物车基础状态State 是存储数据的唯一数据源购物车需存储商品列表每个商品包含核心字段// store/modules/cart.js const state { // 购物车商品列表[{ id, name, price, count, checked, image }] cartList: [] };2Getter派生状态计算属性Getter 用于处理需要实时计算的状态如总价、总数量避免重复逻辑且具备缓存特性const getters { // 购物车商品总数 cartTotalCount: (state) { return state.cartList.reduce((total, item) total item.count, 0); }, // 选中商品的总价 cartSelectedTotalPrice: (state) { return state.cartList .filter(item item.checked) .reduce((total, item) total item.price * item.count, 0) .toFixed(2); // 保留两位小数 }, // 选中商品的数量 cartSelectedCount: (state) { return state.cartList .filter(item item.checked) .reduce((total, item) total item.count, 0); }, // 是否全选 isAllChecked: (state) { if (state.cartList.length 0) return false; return state.cartList.every(item item.checked); } };3Mutation同步修改状态Vuex 规定只能通过 Mutation 修改 State所有同步操作都需定义在 Mutation 中便于调试和追踪const mutations { // 加入购物车 ADD_TO_CART(state, goods) { // 查找商品是否已存在 const existingGoods state.cartList.find(item item.id goods.id); if (existingGoods) { // 存在则累加数量 existingGoods.count goods.count; } else { // 不存在则添加默认选中 state.cartList.push({ ...goods, checked: true }); } // 持久化到本地存储 localStorage.setItem(cartList, JSON.stringify(state.cartList)); }, // 修改商品数量 UPDATE_GOODS_COUNT(state, { id, count }) { const goods state.cartList.find(item item.id id); if (goods) { goods.count Math.max(1, count); // 数量最小为1 localStorage.setItem(cartList, JSON.stringify(state.cartList)); } }, // 删除商品 REMOVE_GOODS(state, id) { state.cartList state.cartList.filter(item item.id ! id); localStorage.setItem(cartList, JSON.stringify(state.cartList)); }, // 切换单个商品选中状态 TOGGLE_GOODS_CHECKED(state, id) { const goods state.cartList.find(item item.id id); if (goods) { goods.checked !goods.checked; localStorage.setItem(cartList, JSON.stringify(state.cartList)); } }, // 全选/取消全选 TOGGLE_ALL_CHECKED(state, isChecked) { state.cartList.forEach(item { item.checked isChecked; }); localStorage.setItem(cartList, JSON.stringify(state.cartList)); }, // 清空购物车 CLEAR_CART(state) { state.cartList []; localStorage.removeItem(cartList); }, // 从本地存储加载购物车 LOAD_CART_FROM_LOCAL(state) { const cartList localStorage.getItem(cartList); if (cartList) { state.cartList JSON.parse(cartList); } } };4Action处理异步 / 复杂逻辑Action 用于处理异步操作如请求接口获取购物车数据或封装复杂的同步逻辑通过commit调用 Mutationconst actions { // 异步加入购物车示例可先请求接口再加入本地 async addToCart({ commit }, goods) { try { // 模拟接口请求验证商品库存、价格等 // const res await api.checkGoods(goods.id); // if (res.code ! 200) throw new Error(res.msg); // 接口请求成功后提交Mutation修改状态 commit(ADD_TO_CART, goods); return { success: true, msg: 加入购物车成功 }; } catch (error) { return { success: false, msg: error.message || 加入购物车失败 }; } }, // 初始化加载购物车 initCart({ commit }) { commit(LOAD_CART_FROM_LOCAL); } };5导出模块export default { namespaced: true, // 开启命名空间避免模块间命名冲突 state, getters, mutations, actions };3. 注册购物车模块store/index.js// store/index.js import { createStore } from vuex; import cart from ./modules/cart; export default createStore({ modules: { cart // 注册购物车模块命名空间为cart } });4. 在 Vue 项目中挂载 Store// main.js import { createApp } from vue; import App from ./App.vue; import store from ./store; const app createApp(App); app.use(store); app.mount(#app);三、组件中使用购物车状态1. 初始化加载购物车在 App.vue 的onMounted中初始化购物车数据!-- App.vue -- script setup import { onMounted } from vue; import { useStore } from vuex; const store useStore(); onMounted(() { store.dispatch(cart/initCart); // 调用命名空间下的action }); /script2. 商品页加入购物车!-- GoodsDetail.vue -- template div classgoods-detail h3{{ goods.name }}/h3 p价格¥{{ goods.price }}/p div classcount button clickcount-- :disabledcount 1-/button span{{ count }}/span button clickcount/button /div button clickaddToCart加入购物车/button /div /template script setup import { ref } from vue; import { useStore } from vuex; import { ElMessage } from element-plus; // 示例UI组件库提示 const store useStore(); // 模拟商品数据 const goods { id: 1, name: Vue实战教程, price: 99, image: xxx.jpg }; const count ref(1); // 加入购物车 const addToCart async () { const res await store.dispatch(cart/addToCart, { ...goods, count: count.value }); if (res.success) { ElMessage.success(res.msg); count.value 1; // 重置数量 } else { ElMessage.error(res.msg); } }; /script3. 购物车页面展示与操作!-- Cart.vue -- template div classcart div classcart-header label input typecheckbox v-modelisAllChecked changetoggleAllChecked / 全选 /label button clickclearCart清空购物车/button /div div classcart-list v-ifcartList.length div classcart-item v-foritem in cartList :keyitem.id label input typecheckbox v-modelitem.checked changetoggleGoodsChecked(item.id) / /label img :srcitem.image alt classgoods-img / div classgoods-name{{ item.name }}/div div classgoods-price¥{{ item.price }}/div div classgoods-count button clickupdateCount(item.id, item.count - 1)-/button span{{ item.count }}/span button clickupdateCount(item.id, item.count 1)/button /div div classgoods-total¥{{ (item.price * item.count).toFixed(2) }}/div button clickremoveGoods(item.id) classremove-btn删除/button /div /div div classcart-empty v-else购物车为空~/div div classcart-footer v-ifcartList.length p选中商品数量{{ cartSelectedCount }}/p p总价¥{{ cartSelectedTotalPrice }}/p button classpay-btn去结算/button /div /div /template script setup import { computed } from vue; import { useStore } from vuex; const store useStore(); // 映射State命名空间下需指定模块 const cartList computed(() store.state.cart.cartList); // 映射Getter const cartSelectedCount computed(() store.getters[cart/cartSelectedCount]); const cartSelectedTotalPrice computed(() store.getters[cart/cartSelectedTotalPrice]); const isAllChecked computed(() store.getters[cart/isAllChecked]); // 全选/取消全选 const toggleAllChecked (e) { store.commit(cart/TOGGLE_ALL_CHECKED, e.target.checked); }; // 切换单个商品选中状态 const toggleGoodsChecked (id) { store.commit(cart/TOGGLE_GOODS_CHECKED, id); }; // 修改商品数量 const updateCount (id, count) { store.commit(cart/UPDATE_GOODS_COUNT, { id, count }); }; // 删除商品 const removeGoods (id) { store.commit(cart/REMOVE_GOODS, id); }; // 清空购物车 const clearCart () { store.commit(cart/CLEAR_CART); }; /script四、关键优化点1. 命名空间namespaced开启namespaced: true后模块的 Getter、Mutation、Action 会自动添加模块名前缀避免多模块下的命名冲突这是大型项目的必备实践。2. 数据持久化通过 localStorage 存储购物车数据页面刷新后调用LOAD_CART_FROM_LOCALmutation 恢复数据生产环境中也可使用vuex-persistedstate插件简化持久化逻辑。3. 边界处理商品数量限制最小为 1避免负数全选状态需判断购物车是否为空避免空数组时every返回true价格计算后保留两位小数符合电商场景需求。4. 异步逻辑封装将接口请求等异步操作放在 Action 中组件只负责触发 Action 和处理结果符合 “状态管理与视图解耦” 的设计思想。五、Vue 3 迁移 Pinia 的思路Vue 3 官方更推荐使用 Pinia 替代 VuexPinia 去掉了 Mutation、简化了模块管理购物车状态管理可无缝迁移// store/cart.jsPinia版本 import { defineStore } from pinia; export const useCartStore defineStore(cart, { state: () ({ cartList: [] }), getters: { // 同Vuex的Getter逻辑 }, actions: { // 直接在actions中修改状态无需Mutation addToCart(goods) { // 原Mutation逻辑 }, // 其他操作方法... } });六、总结购物车的状态管理核心是 “统一数据源 清晰的操作逻辑”State 存储基础数据Getter 处理派生数据Mutation 保证同步修改的可追踪性Action 封装异步 / 复杂逻辑模块拆分、命名空间、数据持久化是实战中的关键优化手段组件只需通过useStoreVuex/useCartStorePinia获取状态和触发操作实现视图与状态的解耦。本文的购物车设计覆盖了电商场景的核心需求你可在此基础上扩展库存校验、优惠券、地址选择等功能进一步完善电商应用的状态管理体系。