前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue3+pinia购物车小例子练习

vue3+pinia购物车小例子练习

作者头像
代码哈士奇
发布2022-05-11 15:02:03
8980
发布2022-05-11 15:02:03
举报
文章被收录于专栏:dmhsq_csdn_blog

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>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • vue3+pinia购物车小例子练习
    • 引入pinia
      • 创建模拟数据获取api文件
        • 创建Car和Shops 的store文件
          • Shops.ts
          • car.ts
        • 使用
          • 页面Shop.vue
          • 组件 Shops.vue
          • 组件 Car.vue
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档