vue3 pinia购物车小例子练习
pinia文档 https://pinia.vuejs.org/introduction.html#a-more-realistic-example
里面有很多不足之处,还望体谅,小练习 实现的效果如下
看了文档 觉得pinia应该很牛逼 如下图
引入pinia
这里使用的 vite创建的vue-ts项目
我用的是 yarn add pinia --save or npm install pinia --save
在mian.ts/main.js 引入pinia
代码语言:javascript复制import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
const app = createApp(App);
app.use(createPinia());
app.mount('#app');
创建模拟数据获取api文件
代码语言:javascript复制interface foodType {
id: string;
title: string;
price: number;
nums: number;
}
const foods: Array<foodType> = [
{ id: 'husky', title: '哈士奇狗', price: 50, nums: 10 },
{ id: 'car', title: '玩具车', price: 10, nums: 15 },
{ id: 'milk', title: '牛奶', price: 30, nums: 5 },
];
const loadFood = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(foods);
}, 1000);
});
};
// @ts-ignore
const getFood: () => Array<foodType> = async function () {
let foods = await loadFood();
return foods as Array<foodType>;
};
export default getFood;
创建Car和Shops 的store文件
分别为 store/Car.ts store/Shops.ts
Shops.ts
代码语言:javascript复制import { defineStore } from 'pinia';
import getFood from '../api/foods';
interface food {
id: string;
title: string;
price: number;
nums: number;
}
interface foods {
[index: string]: food;
}
export const shopStore = defineStore('shop', {
state: () => {
return {
foods: [] as Array<food>,
isLoading: true,
};
},
getters: {
/**
* 数组转对象 方便操作
* @returns foods:{id:{food}}
*/
getShopObj() {
let foods: foods = {};
this.foods.forEach((item) => {
foods[item.id] = item;
});
return foods;
},
},
actions: {
/**
* 异步加载数据
*/
async loadFoods() {
this.foods = await getFood();
this.isLoading = false;
},
/**
* 加入购物车 商品数量减1
* @param id
*/
joinCard(id: string) {
this.foods.forEach((item, index) => {
if (item.id === id) {
if (this.foods[index].nums > 0) {
this.foods[index].nums--;
}
}
});
},
/**
* 购物车商品减少 商品数量加1
* @param id
*/
cardToShop(id: string) {
this.foods.forEach((item, index) => {
if (item.id === id) {
this.foods[index].nums ;
}
});
},
},
});
car.ts
代码语言:javascript复制import { defineStore } from 'pinia';
import { shopStore } from './Shops';
interface food {
id: string;
title: string;
price: number;
nums: number;
}
interface cars {
[index: string]: food;
}
export const carStore = defineStore('car', {
state: () => {
return {
cars: {} as cars,
price: 0,
};
},
getters: {
/**
* 对象转数组 便于展示
*/
carsList(): Array<food> {
let cars = [];
if (!this.cars) {
return [];
}
for (var key in this.cars) {
if (this.cars.hasOwnProperty(key)) {
cars.push(this.cars[key]);
}
}
return cars;
},
/**
* 计算总价
*/
totalPrice() {
let cars: Array<food> = this.carsList;
let total = cars.reduce((all, item) => {
return all item.price * item.nums;
}, 0);
return total;
},
},
actions: {
/**
* 添加到购物车
* @param id
*/
addToCar(id: string) {
const shop = shopStore();
// 获取商品
let foods: cars = shop.getShopObj;
if (foods[id].nums <= 0) {
return;
}
// 商品数量减少
shop.joinCard(id);
// 购物车如果存在商品 数量加1 否则新增
if (this.cars[id]) {
this.cars[id].nums ;
} else {
// 简单深拷贝
this.cars[id] = JSON.parse(JSON.stringify(foods[id]));
this.cars[id].nums = 1;
}
},
/**
* 从购物车减少
* @param id
*/
cudCar(id: string) {
const shop = shopStore();
// 如果只剩下一个就移除 否则就减少一个
if (this.cars[id].nums === 1) {
Reflect.deleteProperty(this.cars, id);
} else {
this.cars[id].nums--;
}
// 商品数量加1
shop.cardToShop(id);
},
},
});
使用
页面Shop.vue
代码语言:javascript复制<template>
<Shops />
<Cars />
</template>
<script>
import Shops from '../components/Shops.vue'
import Cars from '../components/Cars.vue'
export default {
components: { Cars,Shops },
}
</script>
组件 Shops.vue
代码语言:javascript复制<template>
<ul v-if="!isLoading">
<li v-for="item in foods" :key="item.id">
<span>{{item.title}}</span>
<span>单价{{item.price}}</span>
<span>数量{{item.nums}}</span>
<button @click="addToCar(item.id)" :disabled="item.nums===0">加入购物车</button>
</li>
</ul>
<p v-if="isLoading">加载中</p>
</template>
<script>
import {shopStore} from '../store/Shops'
import {carStore} from '../store/Car'
export default {
setup(){
const shops = shopStore();
shops.loadFoods()
const car = carStore()
const addToCar = (id) => {
car.addToCar(id)
}
return {
shops,
addToCar
}
},
computed:{
foods(){
return this.shops.foods
},
isLoading(){
return this.shops.isLoading
}
}
}
</script>
<style>
</style>
组件 Car.vue
代码语言:javascript复制<template>
<h1>购物车</h1>
<ul v-if="carList.length>0">
<li v-for="item in carList" :key="item.id">
<span>{{item.title}}</span>
<span>单价{{item.price}}</span>
<span>数量{{item.nums}}</span>
<button @click="addToCar(item.id)"> </button>
<button @click="cudCar(item.id)">-</button>
</li>
</ul>
<p>总价:{{total}}</p>
</template>
<script>
import {carStore} from '../store/Car'
export default {
setup(){
const car = carStore()
const addToCar = (id) => {
car.addToCar(id)
}
const cudCar = (id) => {
car.cudCar(id)
}
return {
car,
addToCar,cudCar
}
},
computed:{
carList(){
return this.car.carsList
},
total(){
return this.car.totalPrice
}
}
}
</script>
<style>
</style>