zoukankan      html  css  js  c++  java
  • 从零开始,搭建一个简单的购物平台(十七)前端商城部分

    从零开始,搭建一个简单的购物平台(十六)前端商城部分:
    https://blog.csdn.net/time_____/article/details/108769229
    项目源码(持续更新):https://gitee.com/DieHunter/myCode/tree/master/shopping

    上篇文章讲到了商品详情页面实现,最后一个功能是加入购物车,也就是通过列表对比商品是否存在,若存在,则对现有商品数据进行修改,若不存在,则初始化商品,并添加至购物车列表中,这篇文章将介绍对购物车数据进行操作功能

    购物车功能包括
               修改商品数量                        删除单个商品                           全选/反选                               批量删除

    这个页面,将其分解成四个组件,分别是顶部的Title,菜单栏Tabbar,单件商品shopCarItem和下面的批量操作shopCarOrder

    修改商品数量在上篇文章中已介绍,通过countShopItem方法进行修改

    删除单个商品

    delShopItem(_id) {
        let _shopCar = this.state//获取现有购物车列表
        _shopCar.splice(_id, 1)//数组删除第_id项
        this.state = _shopCar//刷新购物车列表
        this.$events.emitEvent(EventName.CountShop);//刷新界面
      }

    全选/反选,这里有两个注意的地方,全选/反选的实现有两种状态,一是每个商品单选被全选或反选后全选按钮也会跟随状态,二是全选按钮全选或反选后所有单选按钮也会跟随状态

    我们首先在store的action加一个方法,用于总计商品的全选状态,商品总数,及总价格。每当商品被选中,就触发这个方法,刷新数据

      filterSelect() {//修改商品全选,单个商品驱动全选按钮,刷新数据
        let shopConfig = {//所有商品总计初始值
          _count: 1,//是否全选
          _selCount: 0,//商品总数
          _sum: 0//商品总价
        }
        this.state.forEach(item => {
          shopConfig._selCount += item.isSelect ? 1 : 0;
          shopConfig._count *= item.isSelect;//判断是否全选,初始值0,若全为false,相乘等于0,若全为true,相乘为1,即等于1是全选,等于0是未全选
          shopConfig._sum += item.isSelect ? item.sum : 0
        });
        this.$events.emitEvent(EventName.SelectParent, shopConfig);
      }

    此外,我们需要再写个方法,用于全选按钮修改各个商品的选中状态

      selAllChild(_sel) {//修改商品全选,全选按钮驱动单个商品,刷新数据
        this.state = this.state.map(item => {
          item.isSelect = _sel;//当全选按钮选中,修改所有商品状态
          return item;
        });
        this.$events.emitEvent(EventName.SelectAllChild);
      }

    于是在单件商品shopCarItem组件中,我们进行调用action中的方法,修改全局state值

    <template>
      <div>
        <ul v-if="shopList.length" class="shopCar">
          <li v-for="(item,index) in shopList" :key="index">
            <span class="mint-checkbox" @click="selectHandler(index)">
              <input class="mint-checkbox-input" type="checkbox" :checked="item.isSelect" />
              <span class="mint-checkbox-core"></span>
            </span>
            <img :src="imgPath+item.shopPic" alt />
            <div class="shopInfo">
              <div>
                <span>{{item.shopName}} {{item.shopScale}}克</span>
                <span>¥{{item.shopPrice}}</span>
              </div>
              <div>
                <mt-button class="minus" type="default" @click="minusShopHandler(item)">-</mt-button>
                <span>{{item.shopCount}}</span>
                <mt-button class="add" type="default" @click="addShopHandler(item)">+</mt-button>
                <mt-button class="del" type="default" @click="delShopHandler(index)">×</mt-button>
              </div>
            </div>
          </li>
        </ul>
        <div v-else class="noShop">
          <div class="icon-jiarugouwuche iconfont"></div>
          <span>购物车为空</span>
        </div>
      </div>
    </template>
    
    <script>
    import Config from "../../config/config";
    import { Toast } from "mint-ui";
    const { EventName } = Config;
    export default {
      name: "shopCarItem",
      data() {
        return {
          shopCar: null,//初始化购物车
          shopList: [],//购物车列表state
          imgPath: Config.RequestPath,//静态文件根目录
          selectAll: false,//全选
        };
      },
      created() {
        this.shopCar = new this.$store.ShopCar();
        this.shopList = this.shopCar.state;
        this.$events.onEvent(EventName.CountShop, this.countHandler);//商品数量监听
        this.$events.onEvent(EventName.SelectAllChild, this.selAllHandler);//商品全选监听
      },
      mounted() {
        this.shopCar.filterSelect();//初始化全选,商品数量,商品总价
      },
      destroyed() {
        this.$events.offEvent(EventName.CountShop, this.countHandler);
        this.$events.offEvent(EventName.SelectAllChild, this.selAllHandler);
      },
      methods: {
        countHandler(res) {//修改商品数量,刷新数据
          this.shopList = this.shopCar.state;
          this.shopCar.filterSelect();
        },
        selectHandler(_id) {//修改商品全选,单个商品驱动全选按钮,刷新数据
          this.shopList[_id].isSelect = !this.shopList[_id].isSelect;
          this.shopCar.state = this.shopList;
          this.shopCar.filterSelect();
        },
        selAllHandler() {//修改商品全选,全选按钮驱动单个商品,刷新数据
          this.shopList = this.shopCar.state;
          this.shopCar.filterSelect();
        },
        addShopHandler(_data) {//添加商品,刷新数据
          _data.shopCount = 1;
          this.shopCar.countShopItem({
            ..._data,
          });
        },
        minusShopHandler(_data) {//减少商品,刷新数据
          _data.shopCount = -1;
          this.shopCar.countShopItem({
            ..._data,
          });
        },
        delShopHandler(_id) {//删除单个商品,刷新数据
          this.shopCar.delShopItem(_id);
        },
      },
    };
    </script>
    
    <style lang="less" scoped>
    @import "../../style/init.less";
    .noShop {
       100%;
      height: 100%;
      text-align: center;
      span {
        .f_s(36);
      }
      div {
        .w(200);
        .h(200);
        border-radius: 100%;
        background: @mainColor;
        .titleFont();
        box-shadow: 5px 5px 8px #777;
        .l_h(200);
        text-align: center;
        margin: 100px auto 20px;
        .f_s(100);
      }
    }
    .shopCar {
      .padbottom(130);
       100%;
      li {
        border-bottom: 1px solid #d3d3d3;
        padding-left: unit(35 / @pxtorem, rem);
        .h(320);
        .mint-checkbox {
          .h(320);
          .l_h(320);
          display: inline-block;
          vertical-align: middle;
        }
        .mint-checkbox-input:checked + .mint-checkbox-core {
          background: #ea3e3c;
          border-color: #ea3e3c;
        }
        img {
          .h(265);
          .w(265);
          margin-left: unit(20 / @pxtorem, rem);
          display: inline-block;
          vertical-align: middle;
          background: #f5f6f5;
        }
        .shopInfo {
          .h(235);
           50%;
          .padtop(30);
          padding-left: unit(10 / @pxtorem, rem);
          display: inline-block;
          vertical-align: middle;
          div:nth-child(1) {
            overflow: hidden;
            span {
              float: left;
            }
            span:nth-child(2) {
              float: right;
            }
          }
          div:nth-child(2) {
            margin-top: unit(85 / @pxtorem, rem);
            span {
              display: inline-block;
              vertical-align: middle;
              padding: 0 unit(50 / @pxtorem, rem);
            }
            .add,
            .minus,
            .del {
              display: inline-block;
              vertical-align: middle;
              background: white;
              box-shadow: none;
              .f_s(50);
            }
            .del {
              float: right;
            }
          }
        }
      }
    }
    </style>

    在批量操作shopCarOrder组件中同理

    <template>
      <div class="shopOrder">
        <span class="mint-checkbox" @click="selectHandler">
          <input class="mint-checkbox-input" type="checkbox" :checked="isSelAll" />
          <span class="mint-checkbox-core"></span>
        </span>
        <span>全选({{selCount}})</span>
        <span @click="delSelShop">删除({{selCount}})</span>
        <span>
          <span>¥{{sum}}</span>
          <span class="icon-qianjin iconfont" @click="sendOrder"></span>
        </span>
      </div>
    </template>
    
    <script>
    import Config from "../../config/config";
    import ShopCarOrderBussiness from "./bussiness";
    import { Toast } from "mint-ui";
    const { EventName } = Config;
    export default {
      name: "shopCarOrder",
      data() {
        return {
          shopCar: null,
          isSelAll: false,//全选
          selCount: 0,//商品数量
          sum: 0,//商品总价
          orderList: null,//提交订单请求参数
          shopCarOrderBussiness: null,
        };
      },
      created() {
        this.shopCar = new this.$store.ShopCar();
        this.shopCarOrderBussiness = new ShopCarOrderBussiness(this);
        this.$events.onEvent(EventName.SelectParent, this.selAllHandler);//全选按钮监听,通过监听所有商品都选中或未全选,修改状态
      },
      destroyed() {
        this.$events.offEvent(EventName.SelectParent, this.selAllHandler);
      },
      methods: {
        selectHandler() {//驱动修改所有商品选中状态
          this.isSelAll = !this.isSelAll;
          this.shopCar.selAllChild(this.isSelAll);
        },
        selAllHandler({ _count, _selCount, _sum }) {
          this.isSelAll = _count;
          this.selCount = _selCount;
          this.sum = _sum;
        },
        delSelShop() {//删除选中商品
          this.shopCar.delSelShop();
        },
        sendOrder() {//提交订单
          this.shopCarOrderBussiness.sendOrderList();
        },
      },
    };
    </script>
    
    <style lang="less" scoped>
    @import "../../style/init.less";
    .shopOrder {
      .f_s(34);
      color: #fff;
      position: fixed;
      .mcolor();
      bottom: unit(130 / @pxtorem, rem);
       100%;
      .h(130);
      .l_h(130);
      > span:nth-child(1),
      > span:nth-child(2) {
        padding-left: unit(35 / @pxtorem, rem);
      }
      > span:nth-child(3) {
        padding-left: unit(200 / @pxtorem, rem);
      }
    
      > span:nth-child(4) {
        float: right;
        margin-right: unit(50 / @pxtorem, rem);
        > span:nth-child(1) {
          padding-left: unit(20 / @pxtorem, rem);
          border-left: 1px dashed #fff;
        }
        > span:nth-child(2) {
          padding-left: unit(50 / @pxtorem, rem);
        }
      }
      > span {
        display: inline-block;
      }
      .mint-checkbox-input + .mint-checkbox-core {
        background: transparent;
        border-color: #fff;
      }
      .mint-checkbox-input:checked + .mint-checkbox-core {
        .mcolor();
      }
    }
    </style>

    在action中,我们还需要写一个函数,用于删除选中商品

    delSelShop() {//直接通过遍历商品选中状态值进行删除,并刷新数据
        let _list = []
        this.state.map(item => {
          if (!item.isSelect) {
            _list.push(item)
          }
        });
        this.state = _list
        this.$events.emitEvent(EventName.CountShop);
      }

    最后,在shopCar.vue界面中引入这四个组件,页面实现完成

    <template>
      <div>
        <Top title="购物车"></Top>
        <div class="content">
          <ShopCarItem></ShopCarItem>
          <ShopCarOrder></ShopCarOrder>
        </div>
        <TabBar></TabBar>
      </div>
    </template>
    
    <script>
    import Top from "../../components/top/top";
    import ShopCarItem from "../../components/shopCarItem/shopCarItem";
    import ShopCarOrder from "../../components/shopCarOrder/shopCarOrder";
    import TabBar from "../../components/tabBar/tabBar";
    export default {
      name: "shopCar",
      data() {
        return {};
      },
      components: {
        Top,
        ShopCarItem,
        ShopCarOrder,
        TabBar
      },
      created() {}
    };
    </script>
    <style lang="less" scoped>
    @import "../../style/init.less";
    </style>

    本篇文章主要对商品购物车操作进行了介绍,其中运用了数据刷新视图的基本操作,将数据,逻辑,视图三者分开,结合vue的数据绑定渲染页面。下篇文章将实现用户的注册,登录功能(简单的用户名密码注册,登录,和邮箱验证模块)

  • 相关阅读:
    pyqt5 动画学习(二) 改变控件颜色
    pyqt5 QGraphicsView颜色动画问题(不兼容,运行不了动画)
    selenium chrome浏览器与chrome.driver的对应关系
    使用tkinter加载png,jpg
    SVN是什么,svn的目录结构
    性能测试中用LambdaProbe监控Tomcat Tomcat和Probe的配置
    Mysql从客户端连接服务器连不上的问题
    已达到计算机的连接数最大值,无法再同此远程计算机连接”的解决办法
    解决远程桌面无法连接的问题
    查看端口是否被打开、占用、开放的有关命令。
  • 原文地址:https://www.cnblogs.com/HelloWorld-Yu/p/13806818.html
Copyright © 2011-2022 走看看