vue3仿美团项目(5)-购物车开发

一、主要实现的功能

1.商品列表

2.结算功能

3.编辑功能

二、结算功能步骤

 1.初始化默认选中项

  2.将步进器中选中数量同步

  3.引入vant结算功能,实现全选和反选(逻辑有些未搞清楚)

  4.计算总价格(注意要*100)

  5.结算但是不生成订单(需要vuex,引入结算列表)

三、编辑功能步骤

  1.进入编辑页面后的删除功能,判断是否有数据,

  2.利用全局总线的方式发布消息,是否可以进入到编辑状态,如果购物车列表数组不为空,则可以进入到编辑页面(myCart、header组件)

  3.修改页面,定义一个isDelete,v-if判断如果为false,则为删除,接收全局总线消息(cartDetails组件)

  4.更新数据,传入type,删除之后更新购物车数组,结算功能中传入2(type==1为删除,type==2为更新)

  5.来回切换(编辑和完成组件之间)

  6. 修改isShow,编辑功能中将购物车所有列表删除完毕之后,显示空组件,头部变成编辑两个字

四、完整代码

 下载 npm i mitt -S

common->js->eventbus.js

import mitt from "mitt"
const emitter=mitt()
export default emitter

components->Header.vue

<template>
  <div class="header">
    <van-icon name="arrow-left" class="icon" />
    <div>{{ title }}</div>
    <div class="edit" v-if="edit" @click="editClick">
      {{ store.state.edit ? "编辑" : "完成" }}
    </div>
  </div>
</template>
<script>
import { defineComponent } from "vue";
import { useStore } from "vuex";
import emitter from "../common/js/evenbus";
import { Toast } from "vant";
export default defineComponent({
  name: "App",
  props: ["title", "edit"],
  setup() {
    const store = useStore();
    const editClick = () => {
      // 判断如果购物车列表不为空,则发布全局事件总线消息,意味着可以进入编辑
      if (store.state.cartList.length) {
        console.log("进入编辑页面");
        store.commit("EDIT");
        emitter.emit("edit");
      } else {
        Toast.fail("购物车空空如也");
      }
    };
    return {
      editClick,
      store,
    };
  },
});
</script>
<style lang="less" scoped>
.header {
  background-color: #fff;
  height: 40px;
  font-size: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
  border-bottom: 1px solid #d7d7d7;
  .icon {
    position: absolute;
    left: 10px;
  }
  .edit {
    position: absolute;
    right: 15px;
    font-size: 18px;
  }
}
</style>

pages->myCart->MyCart.vue

<template>
  <div class="cart">
    <Header title="购物车" :edit="true" />
    <Cart-details v-if="isShow" :changeShow="changeShow" />
    <Blank v-else />
    <Footer />
  </div>
</template>
<script>
import { defineComponent, ref } from "vue";
import Blank from "../../components/Blank.vue";
import Footer from "../../components/Footer.vue";
import Header from "../../components/Header.vue";
import CartDetails from "./component/CartDetails.vue";
import { useStore } from "vuex";
export default defineComponent({
  name: "App",
  components: { Footer, Header, Blank, CartDetails },
  setup() {
    const isShow = ref(false);
    const store = useStore();

    const init = () => {
      if (store.state.cartList.length) {
        isShow.value = true;
      }
    };
    init();
    // 编辑功能中:通知展示商品列表还是空组件
    const changeShow = () => {
      isShow.value = !isShow.value;
    };
    return {
      isShow,
      changeShow,
    };
  },
});
</script>
<style lang="less" scoped>
.cart {
  display: flex;
  flex-flow: column;
  height: 100%;
  .content {
    flex: 1;
    overflow-y: auto;
  }
}

</style>

pages->myCart->component->CartDetails.vue

<template>
  <div class="cartDetails">
    <div class="content">
      <van-checkbox-group
        v-model="result"
        ref="checkboxGroup"
        @change="groupChange"
      >
        <div v-for="(i, index) in store.state.cartList" :key="index">
          <FoodAdd :item="i" :showCheckbox="true" :onChange="onChange" />
        </div>
      </van-checkbox-group>
    </div>
    <!-- 结算 -->
    <van-submit-bar
      :price="allPrice * 100"
      button-text="结算"
      @submit="onSubmit"
      button-color="#ffc400"
      v-if="isDelete"
    >
      <van-checkbox v-model="checked" checked-color="#ffc400" @click="checkAll"
        >全选</van-checkbox
      >
    </van-submit-bar>
    <!-- 删除 -->
    <van-submit-bar
      :price="allPrice * 100"
      button-text="删除"
      button-color="#ffc400"
      @submit="deleteClick"
      v-else
    >
      <van-checkbox
        v-model="checked"
        checked-color="#ffc400"
        @click="checkAll"
        class="edit"
        >全选</van-checkbox
      >
    </van-submit-bar>

    <!-- <Footer /> -->
  </div>
</template>
<script>
import { defineComponent, reactive, toRefs, onMounted, computed } from "vue";
import Footer from "../../../components/Footer.vue";
import FoodAdd from "../../../components/FoodAdd.vue";
import { useStore } from "vuex";
import { Toast } from "vant";
import emitter from "../../../common/js/evenbus";

export default defineComponent({
  name: "App",
  components: { FoodAdd, Footer },
  props: ["changeShow"],
  setup(props) {
    const store = useStore();
    let data = reactive({
      result: [],
      checked: false,
      isDelete: true, //编辑功能中: 是否删除,如果true,显示结算;false,显示删除
    });
    // 1.初始化选中项数组,
    const init = () => {
      data.result = store.state.cartList.map((item) => item.id);
    };
    // 2.将步进器中选中数量同步
    const onChange = (value, detail) => {
      console.log("结算功能value", value);
      console.log("结算功能detail", detail);
      store.state.cartList.map((item) => {
        if (item.id == detail.name) {
          item.num = value;
        }
      });
    };

    // 3.全选
    const checkAll = () => {
      if (data.result.length == store.state.cartList.length) {
        // console.log("data.result.length", data.result.length);
        // console.log("store.state.cartList.length", store.state.cartList.length);
        data.result = [];
        // init();
      } else {
        // data.result = [];
        // console.log("data.result.length", data.result.length);
        // console.log("store.state.cartList.length", store.state.cartList.length);
        init();
      }
    };
    // 3.反选
    const groupChange = () => {
      if (data.result.length == store.state.cartList.length) {
        data.checked = true;
      } else {
        data.checked = false;
      }
    };
    // 4.计算总价格
    const allPrice = computed(() => {
      let constList = store.state.cartList.filter((item) =>
        data.result.includes(item.id)
      );
      let sum = 0;
      constList.forEach((item) => {
        return (sum += item.num * item.price);
      });
      return sum;
    });
    onMounted(() => {
      init();
    });

    // 更新数据,type: 1.删除  2.更新
    const update = (type) => {
      return store.state.cartList.filter((item) => {
        return type == 2
          ? data.result.includes(item.id)
          : !data.result.includes(item.id);
      });
    };
    // 5.结算
    const onSubmit = () => {
      if (data.result.length != 0) {
        console.log("结算完成,但不跳转链接");
        store.commit("PAY", update(2));
      } else {
        Toast.fail("请选择商品");
      }
    };
    // const addClick = () => {};
    // 编辑功能中:删除
    const deleteClick = () => {
      // 如果有商品
      if (data.result.length) {
        // 更新vuex中的cartList,  update方法中的type值(1.删除,2.更新)
        store.commit("DELETE", update(1));
        // 删除后的选中项
        data.result = [];
        if (store.state.cartList.length == 0) {
          // 通知vuex中EDIT方法,进行切换
          store.commit("EDIT", "delete");
          // 调用父组件中切换 isShow 的方法
          props.changeShow();
        }
      } else {
        Toast.fail("请选择要删除的商品!");
      }
    };
    // 接收全局总线消息,监听全局总线中的编辑是否触发
    emitter.on("edit", () => {
      data.isDelete = !data.isDelete;
    });

    return {
      ...toRefs(data),
      store,
      // addClick,
      onChange,
      onSubmit,
      checkAll,
      groupChange,
      allPrice,
      deleteClick,
    };
  },
});
</script>
<style lang="less" scoped>
.cartDetails {
  font-size: 14px;
  flex: 1;
  position: relative;
  overflow-y: auto;
  padding: 20px 20px 55px;
  .content {
    background-color: white;
    border-radius: 10px;
    padding: 10px;
  }
  .van-submit-bar {
    position: fixed;
    bottom: 52px;
  }
  .edit {
    position: fixed;
    left: 15px;
    font-size: 16px;
  }
}
</style>

五、上传git

六、小问题

1.在进入编辑界面后,点击全选按钮,会将所有数据进行删除;但是勾选某一个或几个商品,点击删除按钮,并为出现任何问题,会将对应的数据进行删除。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值