当前位置: 首页 > news >正文

Uniapp + Vue3 + Vite +Uview + Pinia 实现购物车功能(最新附源码保姆级)

Uniapp + Vue3 + Vite +Uview + Pinia 实现购物车功能(最新附源码保姆级)

  • 1、效果展示
  • 2、安装 Pinia 和 Uview
  • 3、配置 Pinia
  • 4、页面展示

1、效果展示


在这里插入图片描述

2、安装 Pinia 和 Uview


官网

https://pinia.vuejs.org/zh/getting-started.html

安装命令

cnpm install pinia

Uiew 的安装以及配置参照我的这篇文章

Uniapp + Vite + Vue3 + uView + Pinia 实现自定义底部 Tabbar(最新保姆级教程)

3、配置 Pinia


  • main.js
import { createPinia } from 'pinia'
const app = createSSRApp(App);
app.use(pinia);
  • cart.js
// src/pages/store/cart/cart.js
import { defineStore } from 'pinia';
import { reactive, computed } from 'vue';export const useCartStore = defineStore('cart', () => {// 用 reactive 管理购物车数据const state = reactive({cartItems: [], // 购物车商品列表allChose: false // 全选状态});// 设置购物车数据const setCartItems = (items) => {state.cartItems = items.map(item => ({...item,isChoose: false, // 初始化为未选中状态num: item.num || 1 // 初始化数量}));saveCartToLocalStorage(); // 每次设置后将数据持久化};// 计算已选中的商品数量const selectedItemsCount = computed(() => {return state.cartItems.filter(item => item.isChoose).reduce((count, item) => count + item.num, 0);});// 计算已选中商品的总价格const totalSelectedPrice = computed(() => {return state.cartItems.filter(item => item.isChoose).reduce((total, item) => total + item.price * item.num, 0);});// 切换商品的选中状态const toggleItemChoose = (item) => {const cartItem = state.cartItems.find(cartItem => cartItem.id === item.id);if (cartItem) {cartItem.isChoose = !cartItem.isChoose;}updateAllChoseStatus(); // 每次切换选中状态后更新全选状态saveCartToLocalStorage();};// 修改商品数量const changeItemQuantity = (item, quantity) => {const cartItem = state.cartItems.find(cartItem => cartItem.id === item.id);if (cartItem) {cartItem.num = quantity;}saveCartToLocalStorage();};// 切换全选状态const toggleAllChose = () => {state.allChose = !state.allChose;state.cartItems.forEach(item => {item.isChoose = state.allChose;});saveCartToLocalStorage();};// 更新全选状态const updateAllChoseStatus = () => {state.allChose = state.cartItems.every(item => item.isChoose);};// 将购物车数据保存到 localStorageconst saveCartToLocalStorage = () => {localStorage.setItem('cartItems', JSON.stringify(state.cartItems));};// 从 localStorage 中恢复购物车数据const loadCartFromLocalStorage = () => {const savedCart = localStorage.getItem('cartItems');if (savedCart) {state.cartItems = JSON.parse(savedCart);}};return {state,setCartItems, // 暴露 setCartItems 方法selectedItemsCount,totalSelectedPrice,toggleItemChoose,changeItemQuantity,toggleAllChose,loadCartFromLocalStorage};
});

4、页面展示


<template><view class=""><view class="card"><template v-for="(item, index) in state.cartItems" :key="index"><view class="cart-data card-shadow"><view><up-checkbox :customStyle="{marginBottom: '8px'}" usedAlone v-model:checked="item.isChoose"@change="toggleItemChoose(item)"></up-checkbox></view><view class="cart-image"><up-image :src="item.image" mode="widthFix" height="200rpx" width="220rpx"radius="10"></up-image></view><view><view class="cart-right"><view style="margin-bottom: 10rpx;">{{item.title}}</view><view style="margin-bottom: 20rpx;font-size: 26rpx;color: #7d7e80;">{{item.type}}</view><view class="" style="display: flex;align-items: center;"><up-text mode="price" :text="item.price"></up-text><view class="" style="width: 10rpx;"></view><up-number-box v-model="item.num" @change="val => changeItemQuantity(item, val.value)"min="1"></up-number-box></view></view></view></view></template></view><view class="foot card"><view class="card-connect"><up-checkbox :customStyle="{marginBottom: '8px'}" usedAlone v-model:checked="state.allChose"@change="toggleAllChose"></up-checkbox><view class="" style="display: flex; align-items: center;"><view style="font-size: 28rpx;">全选</view><view style="padding-left: 20rpx;font-size: 24rpx;">已选{{selectedItemsCount}},合计</view><view class="" style="display: flex;flex: 1;"><up-text mode="price" :text="totalSelectedPrice" color="red" size="18"></up-text></view></view><view class="" style="width: 20rpx;position: relative;"></view><view class="" style="position: absolute;right: 40rpx;"><view class="" style="display: flex;"><up-button type="error" text="去结算" shape="circle" style="width: 150rpx;"></up-button></view></view></view></view></view>
</template><script setup>import {ref,computed,onMounted,watch} from 'vue';import {useCartStore} from '@/pages/store/cart/cart.js'import {storeToRefs} from "pinia";// 使用 Pinia storeconst cartStore = useCartStore();// 获取状态和操作const {state,selectedItemsCount,totalSelectedPrice,} = storeToRefs(cartStore);const {toggleItemChoose,changeItemQuantity,toggleAllChose} = cartStore;onMounted(async () => {// 模拟 API 请求获取购物车数据const response = await fetchCartData();cartStore.setCartItems(response);});// 模拟 API 请求函数async function fetchCartData() {return [{id: 1,isChoose: false,image: "https://gw.alicdn.com/imgextra/i3/2218288872763/O1CN01rN6Cn91WHVIflhWLg_!!2218288872763.jpg",title: "散装土鸡蛋  360枚 40斤",type: "40斤 正负25g",price: 29.9,num: 1},{id: 2,isChoose: false,image: "https://gw.alicdn.com/imgextra/i1/2218288872763/O1CN01DipCdH1WHVIqTtCQR_!!0-item_pic.jpg",title: "散装土鸡蛋  360枚 40斤",type: "40斤 正负25g",price: 29.9,num: 1}];}
</script><style lang="scss" scoped>.foot {position: fixed;bottom: 0;left: 0;width: 90%;/* 占据全宽 */height: 100rpx;/* Tabbar 高度 */background-color: #FFF;display: flex;align-items: center;.card-connect {display: flex;align-items: center;justify-content: space-between;}}.card {margin: 20rpx;padding: 20rpx;background-color: #FFF;border-radius: 20rpx;}.card-shadow {border-radius: 20rpx;box-shadow: 10rpx 10rpx 10rpx 10rpx rgba(0.2, 0.1, 0.2, 0.2);}.cart-data {margin-bottom: 40rpx;padding: 20rpx;display: flex;align-items: center;.cart-image {flex: 1;}.cart-right {display: flex;flex-direction: column;}}
</style>

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Flask 第八课 -- 模板渲染
  • ArrayList 源码解析
  • Python快速入门 —— 第三节:类与对象
  • 手机玩机常识____展讯芯片刷机平台ResearchDownload的一些基本常识与问题解决
  • 【网络安全的神秘世界】渗透测试基础
  • 3. Python计算水仙花数
  • 2848. 与车相交的点(24.9.19)
  • TCP和MQTT通信协议
  • 音视频开发常见的开源项目汇总
  • C语言自定义类型结构体(24)
  • 免费SSL证书正在逐渐被淘汰,证书部署自动化的发展趋势即将到来!
  • LabVIEW中AVI帧转图像数据
  • 从ANN到SNN的转换:实现、原理及两种归一化方法【MINIST、实战】
  • 【JVM】类加载
  • 上海亚商投顾:沪指探底回升 华为产业链午后爆发
  • [LeetCode] Wiggle Sort
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • CentOS7简单部署NFS
  • java中的hashCode
  • Linux链接文件
  • magento2项目上线注意事项
  • opencv python Meanshift 和 Camshift
  • python学习笔记 - ThreadLocal
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • -- 数据结构 顺序表 --Java
  • 微服务入门【系列视频课程】
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • # AI产品经理的自我修养:既懂用户,更懂技术!
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (11)MATLAB PCA+SVM 人脸识别
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (一)认识微服务
  • (一一四)第九章编程练习
  • (转)重识new
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .Net 代码性能 - (1)
  • .NET面试题(二)
  • .Net转Java自学之路—基础巩固篇十三(集合)
  • ::before和::after 常见的用法
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [51nod1610]路径计数
  • [ANT] 项目中应用ANT
  • [BZOJ4566][HAOI2016]找相同字符(SAM)
  • [EULAR文摘] 脊柱放射学持续进展是否显著影响关节功能
  • [FROM COM张]如何解决Nios II SBTE中出现的undefined reference to `xxx'警告
  • [IE6 only]关于Flash/Flex,返回数据产生流错误Error #2032的解决方式
  • [IE编程] IE中对网页进行截图的编程接口
  • [leetcode] Multiply Strings
  • [NOIP 2003] 栈(三种方法:DP、数论、搜索)