vue3 中应用 element plus,pinia 实现简易购物车

    使用pinia 进行全局的状态管理,降低组件之间的耦合性

一、项目需要的资源

1、element plus官方地址:https://element-plus.gitee.io/zh-CN/guide/quickstart.html

2、pinia 官方地址:https://pinia.web3doc.top/introduction.html

      pinia 缓存插件地址:https://prazdevs.github.io/pinia-plugin-persistedstate/guide/

3、vue官方地址:https://cn.vuejs.org/

二、安装插件

1、安装 element plus 

npm i element-plus -- save
//or
yarn add element-plus -- save

 2、安装pinia 和pinia缓存

npm i pinia --save
//or  
yarn add pinia --save


npm i pinia-plugin-persistedstate --save
//or 
yarn add pinia-plugin-persistedstate --save

 三、应用

1、在main.js 中引入pinia、pinia 缓存以及element plus 

import { createApp } from "vue";
import { createPinia } from "pinia";//引入pinia
import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; //pinia 持久化
import App from "./App.vue";

import ElementPlus from "element-plus";//引入element plus
import "element-plus/dist/index.css";//引入element plus 的样式文件
import "default-passive-events";

// import "./assets/main.css";
import "./assets/common.css";

import router from "./router"; // 引入路由
import * as ElementPlusIconsVue from "@element-plus/icons-vue";//引入element plus 中的icon

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); //pinia数据持久化

const app = createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component);
}

app.use(pinia); //pinia 挂载到vue 实例上
app.use(ElementPlus);//element plus 挂载到vue实例上
app.use(router);//路由 挂载到vue 实例上
app.mount("#app");

2、在src文件夹下创建 store/index.js

import { defineStore } from "pinia";//引入pinia

export const useGoodCarStore = defineStore("goodCar", {
  id: "demo",//缓存的key
  state: () => ({ count: 0, listArr: [], selectListArr: [] }),
  getters: {
    double: (state) => state.count * 2,
    // 购物车中的总数量
    totalNum: (state) => {
      let num = 0;
      if (state.selectListArr.length > 0) {
        num = state.selectListArr.reduce((acc, cur) => {
          return acc + cur.num;
        }, 0);
      }
      return num;
    },
    // 购物车中的总价格
    totalPrice: (state) => {
      let price = 0;
      if (state.selectListArr.length > 0) {
        price = state.selectListArr.reduce((acc, cur) => {
          return acc + cur.num * cur.price;
        }, 0);
      }
      return price;
    },
  },
  actions: {
    increment(state) {
      if (this.listArr.length == 0) {
        this.listArr.push({
          ...state,
          num: 1,
        });
      } else {
        let index = this.listArr.findIndex((item) => item.id == state.id);
        if (index != -1) {
          this.listArr[index].num = this.listArr[index].num + 1;
        } else {
          this.listArr.push({
            ...state,
            num: 1,
          });
        }
      }
      console.log("商品数组:", this.listArr);
    },
    // 选中购物车中的商品
    selectGoodCar(state) {
      this.selectListArr = state;
    },
  },
  // 开启数据持久化
  persist: true,
});

3、创建购物车列表页

<template>
  <el-button class="car-btn" type="primary" @click="goToCarPath"
    >跳转至购物车页面</el-button
  >

  <el-table :data="reactiveObj.goodArr" border style="width: 100%">
    <el-table-column prop="id" label="商品id" width="180" />
    <el-table-column prop="name" label="商品名称" width="180" />
    <el-table-column prop="price" label="单价" width="180" />
    <el-table-column prop="storeNum" label="库存数量" />
    <el-table-column prop="desc" label="简介" />
    <el-table-column fixed="right" label="Operations" width="120">
      <template #default="scope">
        <el-button type="primary" size="small" @click="handleClick(scope)"
          >加入购物车</el-button
        >
      </template>
    </el-table-column>
  </el-table>
</template>
<script setup>
import { onMounted, reactive } from "vue";
import { useRouter } from "vue-router";
import { useGoodCarStore } from "../../store/index"; //引入购物车数据

const store = useGoodCarStore();
console.log("store:", store);
// 实例化路由
const router = useRouter();

const reactiveObj = reactive({
  goodArr: [
    {
      id: 1,
      name: "包子",
      storeNum: 100,
      price: 2,
      desc: "皮薄、馅大,十八褶...",
    },
    {
      id: 2,
      name: "饺子",
      storeNum: 2000,
      price: 10,
      desc: "露露远远811111",
    },
    {
      id: 3,
      name: "鸡蛋灌饼",
      storeNum: 20,
      price: 6,
      desc: "牛牛牛牛牛酷酷酷...",
    },
    {
      id: 4,
      name: "馄饨",
      storeNum: 10,
      price: 3,
      desc: "热气腾腾的。。。",
    },
  ],
});

onMounted(() => {
  console.log("挂载数据");
});

// 点击 添加购物车按钮
const handleClick = (obj) => {
  console.log("加入购物车", obj.row);
  //   store.$patch({
  //     count: store.count + 1,
  //   });
  store.increment(obj.row);

  console.log("store.count:", store.count);
};

// 跳转至购物车页面
const goToCarPath = () => {
  router.push({
    path: "/views/goodCarPage",
  });
};
</script>
<style scoped>
.car-btn {
  margin-bottom: 10px;
}
</style>

4、创建购物车页面

<template>
  <el-table
    ref="multipleTableRef"
    :data="carObj.carArr"
    border
    style="width: 100%"
    @selection-change="handleSelectionChange"
  >
    <el-table-column type="selection" width="55" />
    <el-table-column prop="id" label="商品id" width="180" />
    <el-table-column prop="name" label="商品名称" width="180" />
    <el-table-column prop="price" label="单价" width="180" />
    <el-table-column prop="storeNum" label="库存数量" />
    <el-table-column prop="desc" label="简介" />
    <el-table-column fixed="right" label="购买数量">
      <template #default="scope">
        <el-input-number
          v-model.number="scope.row.num"
          :min="1"
          :max="scope.row.storeNum"
          :precision="0"
        />
      </template>
    </el-table-column>
  </el-table>

  <div class="sum-container">
    共<span class="weight-text">{{ store.totalNum }}</span
    >件商品,共<span class="weight-text">{{ store.totalPrice }}</span
    >元
  </div>
</template>

<script setup>
import { reactive, onMounted, ref } from "vue";
import { useGoodCarStore } from "../../store/index"; //引入购物车数据

const store = useGoodCarStore();

console.log("store:", store);
const multipleTableRef = ref(null);

onMounted(() => {
  if (carObj.carArr.length > 0 && store.selectListArr.length > 0) {
    let idsArr = store.selectListArr.map((item) => item.id);

    //之前购物车中选中的内容的回显
    carObj.carArr.map((item) => {
      if (idsArr.includes(item.id)) {
        multipleTableRef.value.toggleRowSelection(item, true);
      } else {
        multipleTableRef.value.toggleRowSelection(item, false);
      }
    });
  }
});

const carObj = reactive({
  carArr: [],
});

carObj.carArr = store.listArr; //购物车数据

// 选择购物车中的商品
const handleSelectionChange = (val) => {
  store.selectGoodCar(val);
};
</script>
<style>
.sum-container {
  padding-top: 10px;
  text-align: right;
}
.weight-text {
  font-weight: 600;
  font-size: 26px;
}
</style>

四、运行效果

1、商品列表页,缓存中没有任何数据

 图一 商品列表页

2、当点击加入 “购物车页面”,缓存中就添加了刚刚加入的商品信息

图二 加入购物车操作

 3、当点击图二中的 “跳转至购物车页面”,页面跳转至购物车列表页

 图三 购物车列表页

4、勾选购物车中的商品,计算商品的数量以及商品需花费的总价格

图四 勾选商品,计算商品总数量及总价格 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Vue3的应用程序,使用Pinia可以方便地实现购物车功能。Pinia是一个基于Vue3的状态管理库,它提供了一种可扩展的状态管理方案,使得开发者可以更轻松地管理应用程序的状态。 步骤如下: 1. 安装Pinia 使用npm或yarn安装Pinia ``` npm install pinia ``` 2. 创建store 在src目录下创建一个store文件夹,然后在其创建一个cart.js文件,用于存储购物车相关的状态和方法。代码演示: ```javascript import { defineStore } from 'pinia'; export const useCartStore = defineStore({ id: 'cart', state: () => ({ items: [], }), getters: { totalPrice() { return this.items.reduce((total, item) => total + item.price * item.quantity, 0); }, }, actions: { addItem(item) { const existingItem = this.items.find((i) => i.id === item.id); if (existingItem) { existingItem.quantity += item.quantity; } else { this.items.push(item); } }, removeItem(item) { this.items = this.items.filter((i) => i.id !== item.id); }, clearCart() { this.items = []; }, }, }); ``` 在这个文件,我们使用defineStore方法来定义一个名为useCartStore的store,其包含了items、totalPrice、addItem、removeItem、clearCart这些状态和方法。 3. 在组件使用store 接下来,在需要使用购物车组件,可以通过useStore方法引入我们刚刚创建的useCartStore。代码演示: ```javascript <template> <div> <h2>购物车</h2> <ul> <li v-for="item in items" :key="item.id"> {{ item.name }} x {{ item.quantity }} - {{ item.price }}元 <button @click="removeItem(item)">删除</button> </li> </ul> <p v-if="totalPrice">总价:{{ totalPrice }}元</p> <p v-else>购物车为空</p> <button @click="clearCart">清空购物车</button> </div> </template> <script> import { useStore } from 'pinia'; import { useCartStore } from '@/store/cart'; export default { setup() { const cartStore = useStore(useCartStore); return { items: cartStore.items, totalPrice: cartStore.totalPrice, addItem: cartStore.addItem, removeItem: cartStore.removeItem, clearCart: cartStore.clearCart, }; }, }; </script> ``` 在这个组件,我们使用useStore方法引入了useCartStore,并将其的items、totalPrice、addItem、removeItem、clearCart等状态和方法绑定到了组件的data选项,以便在模板使用。 4. 在其他组件使用store 在其他需要使用购物车组件,也可以使用useStore方法引入useCartStore,并通过访问其的状态和方法来实现购物车功能。可以实现多个组件共享同一个store的状态和方法。 这样,我们就可以轻松地使用Pinia实现购物车功能了。使用Pinia,我们可以更清晰地管理状态和方法,避免了在组件传递状态和方法的繁琐操作,提高了应用程序的可维护性和扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值