vnat + vue 实现购物车功能(全选、反选、价格处理)

2,159 阅读1分钟

最近使用vant需要实现一个购物车功能,本来准备偷懒网上找一个,最终却没有找到符合需求的;于是自己动手实现了一个 主要实现了:商品的全选、反选以及结算金额的处理 待实现功能:商品数量改变的处理逻辑、购物车商品的编辑

由于后端接口与当前实现的逻辑有所出入,所以将当前逻辑实现记录一下

效果图

使用到的vant组件

import {
  CellGroup,
  Cell,
  Checkbox,
  Card,
  Sticky,
  Stepper,
  Overlay,
  Loading,
  SubmitBar,
} from "vant";

demo源码

<template>
  <div class="goods-carts">
    <van-overlay
      :show="loading"
      style="display: flex; align-items: center; justify-content: center;"
    >
      <van-loading type="spinner" vertical color="#44d9c5" text-color="#44d9c5">
        数据加载中……
      </van-loading>
    </van-overlay>
    <div v-if="list.length === 0" class="nodata"></div>
    <div v-else>
      <van-sticky>
        <van-cell :title="'全部商品(2)'">
          <span v-if="!editing" style="color: #333;">编辑</span>
          <span v-if="editing" style="color: #333;">完成</span>
        </van-cell>
      </van-sticky>
      <div class="carts-item">
        <van-cell-group v-for="item in list" :key="item.id" class="item-group">
          <van-cell :border="false" :title="item.shopName" icon="shop-o" />
          <van-cell style="padding:0" :border="false">
            <van-checkbox
              v-for="goods in item.goods"
              :key="goods.id"
              :value="checkedIds.includes(goods.id)"
              checked-color="#44d9c5"
              class="item-box"
              :label-disabled="true"
              @click="checkItem(goods)"
            >
              <van-card
                :price="goods.price"
                :title="goods.goodsName"
                :thumb="goods.goodsImg"
              >
                <template #num>
                  <van-stepper
                    v-model="goods.num"
                    :max="goods.maxNum"
                    integer
                    style="margin-top: -2vw;"
                    @change="handleChangeNum"
                    @click.native.stop="() => {}"
                  />
                </template>
              </van-card>
            </van-checkbox>
          </van-cell>
        </van-cell-group>
      </div>
      <div class="carts-sub">
        <van-submit-bar
          :price="subPrice"
          button-text="结 算"
          button-color="#44d9c5"
          @submit="onSubmit"
        >
          <van-checkbox
            v-model="checked"
            checked-color="#44d9c5"
            @change="checkAll"
          >
            全选
          </van-checkbox>
        </van-submit-bar>
      </div>
    </div>
  </div>
</template>

<script>
import _ from "lodash";
import {
  CellGroup,
  Cell,
  Checkbox,
  Card,
  Sticky,
  Stepper,
  Overlay,
  Loading,
  SubmitBar,
} from "vant";

export default {
  components: {
    [CellGroup.name]: CellGroup,
    [Cell.name]: Cell,
    [Checkbox.name]: Checkbox,
    [Card.name]: Card,
    [Sticky.name]: Sticky,
    [Stepper.name]: Stepper,
    [Overlay.name]: Overlay,
    [Loading.name]: Loading,
    [SubmitBar.name]: SubmitBar,
  },
  data() {
    return {
      editing: false,
      loading: false,
      checked: false,
      subPrice: 0,
      list: [],
      canCheckNum: 0,
      checkedIds: [],
    };
  },
  created() {
    this.getList();
  },
  methods: {
    handleChangeNum(val) {
      console.log(1111111, val);
    },
    getList() {
      this.loading = true;
      setTimeout(() => {
        this.list = [
          {
            id: 1,
            shopName: "北京大学人民医院",
            goods: [
              {
                id: "EYE_1001",
                goodsName: "护眼仪",
                num: 2,
                maxNum: 10,
                price: 200,
                goodsImg: "https://img.yzcdn.cn/vant/ipad.jpeg",
              },
              {
                id: "EYE_1002",
                goodsName: "眼药水",
                num: 1,
                maxNum: 200,
                price: 25,
                goodsImg: "https://img.yzcdn.cn/vant/ipad.jpeg",
              },
            ],
          },
          {
            id: 2,
            shopName: "测试医院1",
            goods: [
              {
                id: "EYE_1003",
                goodsName: "眼睛框",
                num: 2,
                maxNum: 500,
                price: 10,
                goodsImg: "https://img.yzcdn.cn/vant/ipad.jpeg",
              },
            ],
          },
        ];

        _.map(this.list, (item) => {
          _.map(_.get(item, "goods", []), () => {
            this.canCheckNum++;
          });
        });

        this.loading = false;
      }, 3000);
    },
    checkItem(goods) {
      if (this.checkedIds.includes(goods.id)) {
        this.checkedIds = _.filter(this.checkedIds, (id) => id !== goods.id);
        this.subPrice -= goods.price * 100 * goods.num;
        this.checked = false;
      } else {
        this.checkedIds.push(goods.id);
        this.subPrice += goods.price * 100 * goods.num;
      }
      if (this.checkedIds.length === this.canCheckNum) {
        this.checked = true;
      }
    },
    checkAll(val) {
      if (val) {
        if (this.checkedIds.length !== this.canCheckNum) {
          _.map(this.list, (item) => {
            _.map(_.get(item, "goods", []), (goods) => {
              this.checkedIds.push(goods.id);
              this.subPrice += goods.price * 100 * goods.num;
            });
          });
        }
      } else {
        if (this.checkedIds.length === this.canCheckNum) {
          this.checkedIds = [];
          this.subPrice = 0;
        }
      }
    },
    onSubmit() {},
  },
};
</script>

<style lang="less">
.goods-carts {
  .van-submit-bar__button--danger {
    background: #44d9c5;
    border: none;
  }

  .carts-item {
    .item-group {
      margin: 3vw 0;

      .item-box {
        padding: 2vw 4vw;

        .van-checkbox__label {
          width: 100%;
        }
      }
    }
  }
}
</style>

注:当前源码可直接使用,查看效果;有兴趣的小伙伴可以将剩余功能进行实现