vue3+pinia购物车小例子练习

2022-05-11 15:02:03 浏览数 (1)

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>

0 人点赞