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

news2024/12/22 18:24:47

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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云轴科技ZStack 获鲲鹏应用创新大赛2024上海赛区决赛一等奖

9月13日&#xff0c;鲲鹏应用创新大赛2024上海赛区决赛成功举办。经评委专家从方案创新性、技术领先性、商业前景以及社会价值四个维度严格评审&#xff0c;云轴科技ZStack参赛作品《ZStack鲲鹏原生开发方案》荣获上海赛区企业赛——原生开发赛道&#xff08;互联网&#xff09…

AI大模型系统实战:挑战与应用多领域,人工智能大模型的实际应用场景

AI大模型系统实战&#xff1a;挑战与应用多领域&#xff0c;人工智能大模型的实际应用场景 人工智能的新浪潮中&#xff0c;大模型系统已成为技术革新的重要驱动力。它们以其强大的学习能力和广泛的应用场景&#xff0c;正在重新定义我们与机器交互的方式。本文将深入探讨AI大模…

VS 如何显示构建的时间

Cherno 构建 Hazel 的时候会显示构建时间 VS -> Tools -> Options -> Projects and Solution -> VC Project Settings

UGit:腾讯自研的Git客户端新宠

UGit 是一款专门针对腾讯内部研发环境特点量身定制的 Git 客户端&#xff0c;其目标在于大幅提升开发效率以及确保团队协作的高度流畅性。UGit 能够良好地支持 macOS 10.11 及以上版本、Apple Silicon 以及 Win64 位系统。 可以下载体验一把。 https://ugit.qq.com/zh/index.…

GIS可视化软件:地理信息与遥感领域中的洞察之眼

在地理信息与遥感技术的广阔天地中&#xff0c;可视化软件如同一双洞察世界的明眸&#xff0c;将复杂的数据编织成生动、直观的画卷&#xff0c;为我们揭示地球的奥秘与城市的律动。本文将深入挖掘其技术核心、应用实例、未来趋势&#xff0c;探讨可视化软件如何为地理信息与遥…

电能质量监测装置和防孤岛装置在特斯拉工厂分布式光伏项目的应用

摘要&#xff1a;全球对可再生能源的关注增加&#xff0c;推动了分布式光伏发电系统的普及。这些系统因环保和灵活性而受到青睐&#xff0c;有助于解决能源和环境问题。电能质量在线监测装置和防孤岛保护装置在这些项目中至关重要。监测装置实时跟踪电压和电流&#xff0c;保障…

切换淘宝最新镜像源npm详细讲解

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; 在中国大陆&#xff0c;npm&#xff08;Node Package Manager&#xff09;的默认源由于网络限制&#xff0c;速度可能较慢。为了解决这个问题&#xff0c;淘宝提供了一个镜像源&#xff0c;它同步了 npm 的…

连接数据库(以MySQL为例)

文章目录 前言一、数据库是什么&#xff1f;二、连接步骤 1.手动导入驱动包2.连接数据库总结 前言 面对应用程序的开发&#xff0c;普遍需要保存用户的海量数据。保存粮的库叫粮库&#xff0c;保存水的库叫水库&#xff0c;那么保存数据的库自然叫数据库。有了数据库&#xff0…

Vue的slot插槽(默认插槽、具名插槽、作用域插槽)

目录 1. slot插槽1.1 默认插槽1.2 具名插槽1.3 作用域插槽 1. slot插槽 作用&#xff1a;让父组件可以向子组件指定位置插入html结构&#xff0c;也是一种组件间通信的方式&#xff0c;适用于父组件向子组件传递数据 1.1 默认插槽 Category.vue&#xff1a; 定义一个插槽。…

先楫HPM6750 Windows下VSCode开发环境配置

用的是EVKmini&#xff0c;ft2232作为调试器jtag接口调试 启动start_gui.exe 以hello_world为例&#xff0c;更改一下build path&#xff0c;可以generate并使用gcc compile 最后会得到这些 点击start_gui里面的命令行&#xff0c;用命令行启动vscode 新建.vscode文件夹&…

html+css网页设计 旅游网站首页1个页面

htmlcss网页设计 旅游网站首页1个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#xff…

C++速通LeetCode简单第10题-翻转二叉树

递归法&#xff1a; class Solution { public:TreeNode* invertTree(TreeNode* root) {if (root nullptr) {return nullptr;}TreeNode* left invertTree(root->left);TreeNode* right invertTree(root->right);root->left right;root->right left;return roo…

位段、枚举、联合

位段 在一个结构体中以位&#xff08;最小单位&#xff09;为单位来指定其成员所占的内存长度。位段成员名后面有一个冒号&#xff0c;冒号后有一个数字&#xff08;这个数字是小于等于这个成员所占的位&#xff09;。 typedef struct S {char a : 2;//8char b : 8;//8char c …

基于学习功能聚合的英语口语学习APP

项目介绍 本系统提供文章及朗读的发布、学生跟读及自动评测等功能&#xff0c;促进英语口语学习。 主要包括: 文章朗读:发布文章内容及相应的朗读录音&#xff0c;设定打卡要求&#xff0c;并提供播放功能&#xff1b; 文章跟读:打卡,提供朗读音频播放功能,熟悉后进行跟读,自动…

[苍穹外卖]-11数据可视化接口开发

ECharts Apache ECharts是一款基于JavaScript的数据可视化图表库, 提供直观, 生动,可交互, 可定制的数据可视化图表 入门案例: 使用Echarts, 前端关注图表的配置, 不同的配置影响展示的效果, 后端关注图表所需要的数据格式 <!DOCTYPE html> <html><head>&l…

“架构建模驱动企业管理数字化转型大会”圆满落幕,上海斯歌发布重磅成果!

2024年 9 月 10 日&#xff0c;由上海博阳精讯信息科技有限公司&#xff08;后文简称“博阳精讯”&#xff09;与华为云计算技术有限公司主办&#xff0c;上海斯歌信息技术有限公司&#xff08;后文简称“上海斯歌”&#xff09;、北京凡得科技有限公司&#xff08;“后文简称凡…

【题解】CF1986G1

目录 翻译思路代码关于G2的想法 翻译 原题链接 思路 数据很大&#xff0c;显然两边同时处理&#xff0c;所以要从 p i i \frac{p_{i}}{i} ipi​​下手。   要让 p i i ∗ p j j \frac{p_{i}}{i} * \frac{p_{j}}{j} ipi​​∗jpj​​是整数&#xff0c;每个 p i i \frac{p_…

Leetcode 二叉树中根遍历

采用递归算法&#xff0c;并且用一个向量来存储节点值。 算法C代码如下&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}*…

GLSL 棋盘shader

今日永杰开金 float size 100.;vec2 checkerboard mod(floor(gl_FragCoord.xy / size), 2.);float c mod(checkerboard.x checkerboard.y, 2.);gl_FragColor vec4(vec3(c), 1);或 vec2 uv floor(S * p.xy * vec2(iResolution.x / iResolution.y, 1) / iResolution.xy); …

文件的常用操作

目录 一、文件的常用操作 1、创建文件 2、读文件 3、写文件 4、删除文件 一、文件的常用操作 1、创建文件 需求&#xff1a;在d盘的a目录下创建hi.txt文件&#xff0c;a目录已经创建好 # 需求&#xff1a;在d盘的a目录下创建hi.txt文件&#xff0c;a目录已经创建好 &qu…