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);
  };

  // 将购物车数据保存到 localStorage
  const 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 store
	const 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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/876186.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

搭建Windows下的Rust开发环境

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust编程与项目实战_夏天又到了的博客-CSDN博客 2.1.1 安装vs_buildtools 在Windows系列操作系统中&#xff0c;Rust开发环境需要依…

机器学习课程学习周报十二

机器学习课程学习周报十二 文章目录 机器学习课程学习周报十二摘要Abstract一、机器学习部分1.1 fGAN: General Framework of GAN1.2 CycleGAN1.3 Auto-Encoder1.4 概率论复习&#xff08;一&#xff09; 总结 摘要 本周的学习内容涵盖了fGAN框架、CycleGAN、自编码器以及概率…

Linux | 探索 Linux 信号机制:信号的产生和自定义捕捉

信号是 Linux 操作系统中非常重要的进程控制机制&#xff0c;用来异步通知进程发生某种事件。理解信号的产生、阻塞、递达、捕捉等概念&#xff0c;可以帮助开发者更好地编写健壮的应用程序&#xff0c;避免由于未处理的信号导致程序异常退出。本文将带你从基础概念开始&#x…

数据结构基础详解:哈希表【C语言代码实践篇】开放地址法__拉链法_哈希表的创建_增删查操作详解

文章目录 1.哈希表代码实现之开放地址法1.1 开放地址法创建哈希表1.2 开放地址法之查找1.3 开放地址法之插入1.4 开放地址法之删除 2.哈希表代码实现之链地址法(拉链法)2.1 链地址法之创建哈希表2.2 链地址法之查找2.3 链地址法之插入2.4 链地址法之删除 1.哈希表代码实现之开放…

Mac电脑剪切板在哪里找 苹果电脑剪切板打开教程【详解】

Windows 和 Mac 电脑在使用方式上存在一些差异&#xff0c;许多习惯了 Windows 系统的用户初次接触 Mac 时可能会对某些操作感到困惑。比如&#xff0c;很多人会问&#xff1a;Mac 上的剪贴板在哪里&#xff1f;如果你也有这样的疑问&#xff0c;不妨看看下面这篇关于如何在 Ma…

MySQL查询执行(四):查一行也很慢

假设存在表t&#xff0c;这个表有两个字段id和c&#xff0c;并且我在里面插入了10万行记录。 -- 创建表t CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB;-- 通过存储过程向t写入10w行数据 delimiter ;; create procedure idat…

Android Studio新建工程(Java语言环境)

一、新建工程流程(java语言环境) 1、File->New->New Project 2、选择“Empty Views Activity” -> Next 3、创建项目名称/项目路径/语言环境 1&#xff09;项目名称&#xff1a;使用默认Name 或 修改Name 2) Package name&#xff1a;每个项目的这个名称唯一&…

饿了么基于Flink+Paimon+StarRocks的实时湖仓探索

摘要&#xff1a;本文整理自饿了么大数据架构师、Apache Flink Contributor 王沛斌老师在8月3日 Streaming Lakehouse Meetup Online&#xff08;Paimon x StarRocks&#xff0c;共话实时湖仓架构&#xff09;上的分享。主要分为以下三个内容&#xff1a; 饿了么实时数仓演进之…

self-play RL学习笔记

让AI用随机的路径尝试新的任务&#xff0c;如果效果超预期&#xff0c;那就更新神经网络的权重&#xff0c;使得AI记住多使用这个成功的事件&#xff0c;再开始下一次的尝试。——llya Sutskever 这两天炸裂朋友圈的OpenAI草莓大模型o1和此前代码能力大幅升级的Claude 3.5&…

手机玩机常识____展讯芯片刷机平台ResearchDownload的一些基本常识与问题解决

展讯ResearchDownload工具 展讯芯片的刷机工具--ResearchDownload下载工具"是一款专为用户设计的高效、便捷的下载管理软件&#xff0c;它能够帮助用户快速、稳定地从互联网上获取各种文件。这款工具以其强大的功能和良好的用户体验&#xff0c;在众多展讯芯片下载工具中脱…

Python [ GUI编程自学 ],虽然但是,还是想出一个系列

Python [ GUI编程自学 ]&#xff0c;虽然但是&#xff0c;还是想出一个系列。 目前跟着哔站自学完毕&#xff0c;皮毛了解了&#xff0c;本文GUI一系列文章请查看Python_GUI编程专栏&#xff01; 本篇主要介绍了事件处理机制&#xff1a;事件处理原理&#xff08;感觉和之前学的…

解决win11 使用wsl工具,不能使用systemctl

使用systemctl命令出现报错&#xff1a; System has not been booted with systemd as init system (PID 1). Can‘t operate. 默认情况下并不启用 systemd&#xff0c;而是使用了其他轻量级的初始化系统&#xff08;SysV init初始化系统&#xff09;。这导致一些需要 system…

利用未标记数据的半监督学习在模型训练中的效果评估

数据科学家在实践中经常面临的一个关键挑战是缺乏足够的标记数据来训练可靠且准确的模型。标记数据对于监督学习任务&#xff08;如分类或回归&#xff09;至关重要。但是在许多领域&#xff0c;获取标记数据往往成本高昂、耗时或不切实际。相比之下&#xff0c;未标记数据通常…

Java获取随机数

在Java中获取随机数通常会使用java.util.Random类或者Math.random()方法 1.java.util.Random java.util.Random类用于生成伪随机数。 // 使用无参构造方法创建Random对象Random rand new Random();// 生成一个[0, 100)范围内的随机整数int randomInt rand.nextInt(100);Sys…

linux使用命令行编译qt.cpp

步骤&#xff1a; mkdir qttestcd qttestvim hello.cpp #include <QApplication> #include <QDialog> #include <QLabel> int main(int argc,char* argv[]) {QApplication a(argc,argv);QLabel label("aaa");label.resize(100,100);label.show()…

vulnhub(6):Tr0ll(隐藏目录、hydra密码爆破、内核漏洞提权)

端口 nmap主机发现 nmap -sn 192.168.178.0/24 ​ Nmap scan report for 192.168.178.33 Host is up (0.00020s latency). ​ 33是新出现的机器&#xff0c;他就是靶机 nmap端口扫描 nmap -Pn 192.168.178.33 -p- --min-rate 10000 -oA nmap/scan 扫描开放端口保存到 nmap/sca…

【FATFS】FATFS简介及下载

1、FATFS简介 FatFs 是一个针对嵌入式系统开发的通用文件系统模块&#xff0c;主要用于支持 FAT 文件系统。它最初由 ChaN 开发&#xff0c;并被广泛应用于嵌入式设备上。FatFs 以其轻量级、可配置和设备无关的特性著称&#xff0c;支持 FAT12、FAT16、FAT32 以及 exFAT 文件系…

【iOS】单例模式

目录 前言单例模式认识单例模式单例模式的特点及使用情景单例模式的使用单例模式的实现步骤&#xff1a;完整代码 总结 前言 在进行大项目编写之前&#xff0c;开始对前面比较重要的知识进行回顾和重新学习&#xff0c;单例模式在软件开发设计中是比较重要的&#xff0c;尤其是…

EFI引导模式下配置Windows和Linux双系统共存

这几天在VirtualBox虚机里玩Modular MAX下的LLama3大模型&#xff0c;实在受不了这执行速度&#xff0c;于是下决心把Ubuntu系统安装在硬盘上跟Windows11做双系统共存。之前在传统BIOS引导模式下做过不少次双系统引导&#xff0c;EFI模式下第一次做&#xff0c;加之windows系统…

计算机毕业设计 大学志愿填报系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…