小程序购物车功能(支持手动输入数量)以及侧边栏和列表栏联动的实现

小组刚完成一个小程序项目,第一版正式发布了,过程中也遇到了很多问题,这里记录一下我负责的模块中的购物车功能的实现过程。后期再把其他小伙伴的模块也一并贴上来分析一下,自己也学习一下他们的独门技能!效果图如下:

在这里,计数器、购物篮做成组件用于复用,由于左右联动的功能在另一个模块也有用到,所以就把这个功能也做成了一个组件,传入不通的数据即可,左右联动的实现方法在之前一片博客有写到

https://blog.csdn.net/dongguan_123/article/details/80598107

这篇博客主要讲一下选择商品的功能,以及支持手动输入的功能实现

数量选择器

结构上采用左、中、右结构,加减号分别绑定两个事件,中间输入框绑定获取焦点、失去焦点和change事件,用于支持手动输入数量

<view class="wrapper">
    <view class="num-choose {{totalNum || change ? 'active': ''}}">
        <view class="minus {{totalNum || change ? 'active': ''}}" catchtap="minusHandle"             
          data-goodsId="{{goodsId}}">
            <tty-icon type="control-reduce"></tty-icon>
        </view>
        <view class="task task-left"></view>
        <input class="num" wx:if="{{totalNum || change}}" type="number" maxlength="4" 
          bindinput="changeNum"
         value="{{totalNum}}" bindfocus="focusNum" bindblur="blurNum" data-goodsId="
           {{goodsId}}"></input>
            <view class="task task-right"></view>
        <view class="plus" catchtap="plusHandle" data-goodsId="{{goodsId}}">
            <tty-icon type="control-community"></tty-icon>
        </view>
    </view>
</view>

作为组件,事件必须传导到最上层,在那里对数据进行处理

methods: {
    plusHandle(e) { // 增加事件
      let {totalNum, typeOneIndex, typeTwoIndex, goodsIndex, totalStock} = this.data
      let goodsId = e.currentTarget.dataset.goodsid;
      // let pageX = e.touches[0].pageX;
      // let pageY = e.touches[0].pageY;
      totalNum++;
      if (totalStock === 0) {
        wx.showToast({
          title: '请增加库存!',
          icon: 'none',
          duration: 1500
        })
        return
      }
      if (totalNum > totalStock) { // 超过库存
        wx.showToast({
          title: '库存不足,请增加库存!',
          icon: 'none',
          duration: 1500
        })
        return
      }
      this.setData({
        totalNum,
        change: false
      });
      let myEventDetail = {
        goodsId: goodsId,
        // pageX: pageX,
        // pageY: pageY,
        totalNum: totalNum,
        typeOneIndex: typeOneIndex,
        typeTwoIndex: typeTwoIndex,
        goodsIndex: goodsIndex,
        action: 'plus' // 增加事件标记
      }; // detail对象,提供给事件监听函数
      this.triggerEvent('StepperEvent', myEventDetail) // 触发父级事件
    },
    focusNum(e) {
      // 手动输入时获取基础数据
      this.triggerEvent('StepperEvent', {
        action: 'getNum',
        num: Number(e.detail.value)
      });
    },
    blurNum(e) {
      // 失去焦点,改变状态
      this.setData({
        change: false
      });
      // 购物篮失去焦点,商品数为0则清空
      let myEventDetail = {}
      let goodsId = e.currentTarget.dataset.goodsid;
      myEventDetail = {
        goodsId: goodsId,
        action: 'blur'
      };
      this.triggerEvent('StepperEvent', myEventDetail)
    },
    changeNum(e) {
      let num = Number(e.detail.value)
      let {typeOneIndex, typeTwoIndex, goodsIndex, totalStock} = this.data
      let goodsId = e.currentTarget.dataset.goodsid;
      let myEventDetail = {}
      let totalNum = 0;
      if (num > totalStock) { // 超过库存
        wx.showToast({
          title: '库存不足,请增加库存!',
          icon: 'none',
          duration: 1500
        })
        this.setData({
          totalNum: num,
          change: false
        });
        totalNum = totalStock;
      } else {
        totalNum = num;
      }
      myEventDetail = {
        goodsId: goodsId,
        totalNum: totalNum,
        typeOneIndex: typeOneIndex,
        typeTwoIndex: typeTwoIndex,
        goodsIndex: goodsIndex,
        action: 'change'
      };
      this.setData({
        totalNum: totalNum,
        change: true
      });
      this.triggerEvent('StepperEvent', myEventDetail)
    },
    minusHandle(e) {
      let num = this.data.totalNum;
      let {typeOneIndex, typeTwoIndex, goodsIndex} = this.data
      let goodsId = e.currentTarget.dataset.goodsid;
      if (num <= 0) {
        return
      }
      num--;
      let myEventDetail = {
        goodsId: goodsId,
        totalNum: num,
        typeOneIndex: typeOneIndex,
        typeTwoIndex: typeTwoIndex,
        goodsIndex: goodsIndex,
        action: 'minus'
      };
      this.setData({
        totalNum: num,
        change: false
      });
      this.triggerEvent('StepperEvent', myEventDetail);
    }
  }

stemper组件是linkPage(商品左右联动)组件的子组件,需要在linkPage里过渡一下

linkPage.wxml

<view class="stepper" wx:if="{{!management}}">
    <tty-stepper size="small" goodsId="{{pes.goods_id}}" typeOneIndex="{{typeOneIndex}}"     
       typeTwoIndex="{{typeTwoIndex}}" goodsIndex="{{goodsIndex}}" totalStock="
       {{pes.stock}}" totalNum="{{pes.count}}" bindStepperEvent="stepperEvent">
    </tty-stepper>
</view>

linkPage.js

stepperEvent(e) {
      let myEventDetail = e.detail;
      if(myEventDetail.action === 'blur') return
      this.triggerEvent('ContentEvent', myEventDetail)
    }

购物篮和列表栏的触发事件要有所区分

choose-goods.wxml

最后所有数据汇集到主页面进行处理

choose-goods.js  根据事件标记区分是哪一类事件,进行不同的处理

/*商品列表添加事件*/
  contentEvent(e) {
    let {totalNum, action, typeOneIndex, typeTwoIndex, goodsIndex} = e.detail;
    if (action === 'getNum' || action === 'blur') {
      this.setData({ // 获取总基数
        basePageTotalNum: this.data.pageTotalNum - e.detail.num
      });
      return
    }
    if (action === 'overStock') {
      Dialog({
        message: '该商品库存不够啦~',
        confirmButtonText: '我知道了',
        selector: '#tty-dialog-msg'
      }).then(() => {});
      return
    }
    this.addGoods(totalNum, action, typeOneIndex, typeTwoIndex, goodsIndex);
  },
  /*添加商品*/
  addGoods(totalNum, action, typeOneIndex, typeTwoIndex, goodsIndex) {
    let {typeData, goodsData, pageTotalNum} = this.data;
    let goods = typeData[typeOneIndex].goods_category_two[typeTwoIndex].goods[goodsIndex];
    typeData[typeOneIndex].goods_category_two[typeTwoIndex].goods[goodsIndex].count = totalNum;
    if (action === 'plus') {
      pageTotalNum++; // 商品总数
    } else if (action === 'minus') {
      pageTotalNum--;
    } else if (action === 'change') {
      pageTotalNum = this.data.basePageTotalNum + totalNum;
    }
    if (pageTotalNum < 0) {
      pageTotalNum = 0;
      return
    }
    goods.count = totalNum;
    goods.typeOneIndex = typeOneIndex;
    goods.typeTwoIndex = typeTwoIndex;
    goods.goodsIndex = goodsIndex;
    if (totalNum === 1 && action === 'plus') { // 购物篮里没有,则新增
      goodsData.unshift(goods);
    } else {
      if(goodsData.includes(goods)) { // 如果购物篮中已有商品,在原有基础上加1
        let index = goodsData.indexOf(goods)
        totalNum === 0 ? goodsData.splice(index, 1) : goodsData[index].count = totalNum;
      }else { // 如果购物篮中没有,则添加(针对手动修改)
        goodsData.unshift(goods);
      }
    }

    this.setData({
      goodsData,
      typeData,
      pageTotalNum,
      basePageTotalNum: pageTotalNum - totalNum
    });
    this.calculateMoney(goodsData);
  }
/*购物框添加事件*/
  basketEvent(e) {
    if (e.detail.action === 'getNum') {
      this.setData({ // 获取计算基数
        basePageTotalNum: this.data.pageTotalNum - e.detail.num
      });
      return
    }
    let {
      totalNum, // 商品选择的数量
      goodsId, // 修改商品时对应的商品id
      action // 操作行为
    } = e.detail;
    let {
      typeData, // 列表数据
      goodsData, // 购物篮数据
      pageTotalNum // 页面商品总数
    } = this.data;

    if (action === 'plus') {
      pageTotalNum++;
    } else if (action === 'minus') {
      pageTotalNum--;
    } else if (action === 'change') {
      pageTotalNum = this.data.basePageTotalNum + totalNum;
    }
    if (pageTotalNum < 0) {
      pageTotalNum = 0;
    }
    for (let i = 0; i < goodsData.length; i++) {
      if (goodsData[i].goods_id === goodsId) {
        // 获取索引,处理列表商品数量
        let typeOneIndex = goodsData[i].typeOneIndex;
        let typeTwoIndex = goodsData[i].typeTwoIndex;
        let goodsIndex = goodsData[i].goodsIndex;
        let count = 0;
        
        if (action === 'plus') {
          goodsData[i].count++;
          count = goodsData[i].count
        } else if (action === 'minus') {
          goodsData[i].count--;
          count = goodsData[i].count
          if (goodsData[i].count <= 0) {
            goodsData[i].count = 0;
            goodsData.splice(i, 1);
          }
        } else if (action === 'change') {
          if(totalNum <= 0) {
            goodsData[i].count = 0;
          }else {
            goodsData[i].count = totalNum;
          }
          count = goodsData[i].count
          // 失去焦点,数量为0,删除
        } else if (action === 'blur' && goodsData[i].count === 0) {
          count = goodsData[i].count
          goodsData.splice(i, 1);
        }
        typeData[typeOneIndex].goods_category_two[typeTwoIndex].goods[goodsIndex].count = count;
      }
    }

    this.setData({
      goodsData,
      typeData,
      pageTotalNum,
      basePageTotalNum: pageTotalNum - totalNum
    });
    this.calculateMoney(goodsData);// 计算总金额
  }

列表栏中添加商品时,购物篮中没有商品,跟随列表栏变化而变化,属于正向计算,比较简单,有则加1,无则新增

反过来,购物篮中修改数据时就麻烦些了,需要拿到对应的商品id,反向查找列表栏中的商品,并做修改

由上面的效果图可以知道,数据的格式是三层嵌套的数组,这就导致数据的查找比较麻烦,必须循环遍历才能找到最底层的数据

"data": [{
      goods_category_one_id: "221310651891449856",
      goods_category_one_name: "农药",
      goods_category_two: [
        {
          goods_category_two_id: "221310651891449858",
          goods_category_two_name: "杀虫剂",
          goods: [{
            amount: 0,
            base_unit_id: "221310649857212419",
            base_unit_name: "桶",
            count: 0,
            goods_id: "258169085668364288",
            goods_name: "联苯·虫螨腈",
            goods_spec: "",
            price: 3.5,
            stock: 24,
            url: ""
          }]
        },
        {
          goods_category_two_id: "221310651891449859",
          goods_category_two_name: "杀菌剂",
          goods: [{
              amount: 0,
              base_unit_id: "221310649857212422",
              base_unit_name: "克",
              count: 0,
              goods_id: "258168407638147072",
              goods_name: "联苯·虫螨腈",
              goods_spec: "",
              price: 3.5,
              stock: 24,
              url: ""
            },
            {
              amount: 0,
              base_unit_id: "221310649857212421",
              base_unit_name: "克",
              count: 0,
              goods_id: "259282725129682944",
              goods_name: "速克灵100g",
              goods_spec: "",
              price: 5.6,
              stock: 0,
              url: ""
            },
            {
              amount: 0,
              base_unit_id: "221310649857212420",
              base_unit_name: "盒",
              count: 0,
              goods_id: "259285646445645824",
              goods_name: "解决",
              goods_spec: "",
              price: 56,
              stock: 12,
              url: ""
            }
          ]
        }
      ]
    }

项目地址https://github.com/LandQ123/littleProgressChooseGoods

发布了59 篇原创文章 · 获赞 29 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/dongguan_123/article/details/82705824