两种方法jquery, vue构建购物车

我用两种方法构建了购物车页面,分别是jquery和vue。

1. 分析页面逻辑

1.1 设计图如下:

图1:
image.png

图2:
image.png

图3:
image.png

可以整理出功能有这些:

  • 基础的页面渲染,将商品列表渲染到页面上,这步不赘述啦
  • 点击商品条目中的+,-号:商品【数量增减】,(且注意数量不能减为0),下端总价和总数实时更新
  • 点击商品条目的input:* 商品【选中】,下端总价和总数实时更新,存储选中的商品id;
    (若有商品被选中,右下按钮变色,可被点击)
  • 点击页面图1右上角【编辑】:右下角的下单按钮变成删除,进入编辑状态
  • 点击右下按钮,【删除】或【下单】:需设置状态变量state,判断页面是否处于编辑状态,再调用相应接口
1.2 终上所述,我们需要定义的全局变量有:
goods: [],               //暂存接口返回的商品列表,用于渲染页面
state: 0,                 //0:商品选择状态,1:编辑状态
selectIds: [],           //被选中的商品id列表,用于传给下单或删除接口。
readyToOrder: 0,   //有选中的商品,可以下单
totPrice: 0.00,        //选中商品总价
totNum: 0              //选中商品总数

2. vue构建方法

2.1 商品数量增减

这里用商品数量减少做例子,首先在html中用【v-on:click】(简写成@click)属性在-的div上绑定 minus()方法,并传商品id进函数。
如果对v-on事件处理不熟悉阔以点这里

         <div class="good-num">
            <div class="add" @click="add(good.id)">+</div>
            <div class="num" goodId="">{{good.goodsNum}}</div>
            <div class="minus" @click="minus(good.id)">-</div>
          </div>

再来进入js部分,我将minus方法的代码分成前端后端两部分。
前端部分即前端保存的商品列表中该商品数量的减少,
后端部分即与后端交互,调用数量更新接口,改动数据库中该用户购物车中该商品的数量。

        /*
         *商品数量减少
         */
        minus(id) {
          /* front-end */
          var num = 0;           //改后的数量
          for(var i=0;i<this.goods.length;i++) {
            if(this.goods[i].id == id) {
              this.goods[i].goodsNum--;
              this.totNum--;
              this.totPrice -= this.goods[i].price;
              num = this.goods[i].goodsNum;
            }
          }
          /* back-end */
          var numObject = {
            id: id,
            goodsNum: num
          };
          this.$http.post('/shoppingCart/shoppingCartUpdate', numObject).then(res => {
            console.log(res);
          }).catch(error => {
            console.log(error);
          });
        },

未完待续嗷嗷.................


2.2
2.3
2.4
2.x 完整的【购物车组件】代码
<template>
  <div id="purchasingShoppingCart">
    <header>
        <p>购物车</p>
        <div v-if="this.state==0"
             class="edit"
             @click="edit()">编辑
        </div>
        <div v-else class="edit"
             @click="edit()">完成
        </div>
    </header>

    <ul class="good-list">
      <li v-for="(good,index) in goods" :key="index">
        <label class="ql-ipt">
          <input type="checkbox"
                 class="comman-ipt"
                 @click="select(good.id)"><i></i></input>
        </label>
        <a @click="toDetail(good.id)">
          <img class="good-img"
              v-bind:src="'http://120.78.133.190'+good.pic"></img>
          <div class="good-info">
            <p class="good-title">{{good.name}}</p>
            <p class="good-detail">{{good.description}}</p>
            <p class="good-price">¥{{good.price}}</p>
          </div>
        </a>
        <div class="good-num-container">
          <div class="good-num">
            <div class="add" @click="add(good.id)">+</div>
            <div class="num" goodId="">{{good.goodsNum}}</div>
            <div class="minus" @click="minus(good.id)">-</div>
          </div>
        </div>
      </li>
    </ul>

    <div class="bottom">
        <!--label class="ql-ipt final-input">
          <input type="checkbox" class="fin-ipt"><i></i></input>
        </label-->
        <p class="bottom-text">已选 ( <span class="bottom-span">{{totNum}}</span> )</p>
        <p class="tot-price">¥<span class="bottom-price">{{totPrice}}</span></p>
        <button v-if="this.state==0"
                class="sub-btn"
                v-bind:class="{ green: selectIds.length }"
                @click="subOrDel()">下单
        </button>
        <button v-else
                class="sub-btn"
                v-bind:class="{ green: selectIds.length }"
                @click="subOrDel()">删除所选
        </button>
    </div>
  </div>
</template>

<script>
import Vue from 'vue'
    export default {
      name: 'purchasingShoppingCart',
      data () {
        return {
          goods: [],
          state: 0,        //0:选择状态,1:编辑状态
          selectIds: [],
          readyToOrder: 0, //有选中的商品,可以下单
          totPrice: 0.00,
          totNum: 0
        }
      },
      created () {
        /**
          *请求购物车列表
          */
        var cartObject = {
          "buyerId": 1
        };
        this.$http.post('/shoppingCart/shoppingCartList', cartObject).then(res => {
          console.log(res);
          this.goods = res.data.shoppingCartList;
          // 为商品赋选中状态初始值
          this.goods.forEach(function(element) {
            Vue.set(element,'selected',0);
          });
        }).catch(error => {
          console.log(error);
        });
      },
      methods: {
        /*
         *点击购物车条目跳转至商品详情
         */
        toDetail(id) {
          this.$router.push({
            path: "/storeDetail",
            query: {
              goodId: id
            }
          })
        },
        /**
          *选中一件商品
          */
        select(id) {
          var index = 0;
          /* 记录该商品在goods中的下标*/
          for(var i=0;i<this.goods.length;i++) {
            if(this.goods[i].id == id) {
              index = i;
            }
          }
          /* 记录selectIds */
          if(this.goods[index].selected == 0) {
            this.selectIds.push(id);
            console.log(this.selectIds);
            this.goods[index].selected = 1;

            this.totNum += this.goods[index].goodsNum;
            this.totPrice += this.goods[index].goodsNum * this.goods[index].price;
          } else {
            var j = this.selectIds.indexOf(id);
            this.selectIds.splice(j, 1);
            console.log(this.selectIds);
            this.goods[index].selected = 0;

            this.totNum -= this.goods[index].goodsNum;
            this.totPrice -= this.goods[index].goodsNum * this.goods[index].price;
          }
        },
        /*
         *商品数量减少
         */
        minus(id) {
          /* front-end */
          var num = 0;           //改后的数量
          for(var i=0;i<this.goods.length;i++) {
            if(this.goods[i].id == id) {
              this.goods[i].goodsNum--;
              this.totNum--;
              this.totPrice -= this.goods[i].price;
              num = this.goods[i].goodsNum;
            }
          }
          /* back-end */
          var numObject = {
            id: id,
            goodsNum: num
          };
          this.$http.post('/shoppingCart/shoppingCartUpdate', numObject).then(res => {
            console.log(res);
          }).catch(error => {
            console.log(error);
          });
        },
        /*
         *商品数量增加
         */
        add(id) {
          /* front-end */
          var num = 0;           //改后的数量
          for(var i=0;i<this.goods.length;i++) {
            if(this.goods[i].id == id) {
              this.goods[i].goodsNum++;
              this.totNum++;
              this.totPrice += this.goods[i].price;
              num = this.goods[i].goodsNum;
            }
          }
          /* back-end */
          var numObject = {
            id: id,
            goodsNum: num
          };
          this.$http.post('/shoppingCart/shoppingCartUpdate', numObject).then(res => {
            console.log(res);
          }).catch(error => {
            console.log(error);
          });
        },
        /**
          *点击编辑按钮
          */
        edit() {
          /* 编辑/编辑完成 */
          if(this.state == 0) {
              this.state = 1;
          } else {
              this.state = 0;
          }
        },
        /**
          *底部按钮
          *删除或下单
          */
        subOrDel() {
          var sidObject ={
            ids: JSON.parse(JSON.stringify(this.selectIds).replace(/\"/g, ""))
          };
          if(this.state == 0) {
            this.$http.post('/shoppingCart/placeOrder', sidObject).then(res => {
              console.log(res);
              //下单商品暂存
              localStorage.setItem("goods",JSON.stringify(res.data.data));
              localStorage.setItem("price",this,totPrice);

            }).catch(error => {
              console.log(error);
            });
          } else {
            this.$http.post('/shoppingCart/shoppingCartRemove', sidObject).then(res => {
              console.log(res);
            }).catch(error => {
              console.log(error);
            });
          }
          /* 重新请求商品列表 */
          var cartObject = {
            "buyerId": 1
          };
          this.$http.post('/shoppingCart/shoppingCartList', cartObject).then(res => {
            console.log(res);
            this.goods = res.data.shoppingCartList;
            // 为商品赋选中状态初始值
            this.goods.forEach(function(element) {
              Vue.set(element,'selected',0);
            });

            /*
            *局部刷新?
            *清空input的记录,恢复到一切都不选中的状态
            *总价总数恢复0
            *
            */

            this.$router.push({
              path: "/purchasingOrder",
              query: {

              }
            })
          }).catch(error => {
            console.log(error);
          });
        }
      }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#purchasingShoppingCart {
    background-color: #fafafa;
}
/* header */
header {
    height:0.74rem;
    width: 100%;
    color: #ffffff;
    position: fixed;
    top:0;
    font-size: 0.26rem;
    z-index: 2;  /*使fixed覆盖在absolute上层,一直可见*/
    background-color: #5f6d61;
}
header p {
    text-align: center;
    padding-top: 0.24rem;
}
.edit {
    position: absolute;
    right: 0;
    top: 0.24rem;
    right: 0.28rem;
}


/* 商品列表 */
.good-list {
    width: 100%;
    position: absolute;
    top: 0.74rem;
    background-color: #fafafa;
    margin-bottom: 1.74rem;
}
.good-list li {
    height: 1.96rem;
    width: 100%;
    background-color: #ffffff;
    border-bottom: 0.02rem solid #dddddd;
    margin-bottom: 0.12rem;
}
.good-img {
    box-sizing: border-box;
    height: 1.12rem;
    width: 1.26rem;
    position: absolute;
    left: 0.70rem;
    margin-top: 0.36rem;
    border: 0.02rem solid #dddddd;
}
.good-info {
    position: absolute;
    left: 2.22rem;
    margin-top: 0.36rem;
    width: 2.50rem;
    height: 1.12rem;
}
.good-title {
    font-size: 0.24rem;
    position: absolute;
    top: 0;
    margin-bottom: 0.14rem;
}
.good-detail{
    color: #cccccc;
    font-size: 0.16rem;
    position: absolute;
    top: 0.45rem;
}
.good-price {
    color: #e51a19;
    font-size: 0.16rem;
    position: absolute;
    bottom: 0;
}
.good-num-container {
    position: absolute;
    right: 0.44rem;
    margin-top: 0.36rem;
    width: 1.3rem;
    height: 1.12rem;
}
.good-num {
    box-sizing: border-box;
    width: 1.20rem;
    height:0.30rem;
    position: absolute;
    bottom: 0;
    margin-top: 1.22rem;
    border: 0.01rem solid #8e8561;
    text-align: center;
}
.add {
    position: absolute;
    right: 0;
    width: 0.36rem;
}
.add span {
    color: #8e8561;
    font-size: 0.28rem;
    position: absolute;
    bottom: -0.32rem;
    right:0.08rem;
    text-align: center;
}
.num {
    height:0.28rem;
    box-sizing: border-box;
    position: absolute;
    right: 0.36rem;
    border-left: 0.01rem solid #8e8561;
    border-right: 0.01rem solid #8e8561;
    width: 0.48rem;
}
.minus {
    position: absolute;
    right: 0.84rem;
    width: 0.36rem;
}
.minus span {
    color: #8e8561;
    font-size: 0.28rem;
    position: absolute;
    bottom: -0.32rem;
    right:0.10rem;
    text-align: center;
}

/* input */
.ql-ipt input[type='radio'] + i, input[type='checkbox'] + i {
    position: absolute;
    left: 0.18rem;
    margin-top: 0.72rem;
}
.ql-ipt input[type='radio']:checked + i,
input[type='checkbox']:checked + i {
    /* background-color: #8e8561;; */
    background-position: 0 0;
}
.final-input input[type='checkbox'] + i {
    margin-top: 0.38rem;
}

/* bottom part 即下单处 */
.bottom {
    height: 1.06rem;
    width: 100%;
    border-top: 0.02rem solid #dddddd;
    position: fixed;
    bottom: 0rem;
    background-color: #ffffff;
}
.bottom-text {
    position: absolute;
    left: 0.70rem;
    margin-top: 0.40rem;
    font-size: 0.26rem;
}
.bottom-text span {
    font-size: 0.26rem;
}
.tot-price {
    margin-top: 0.40rem;
    position: absolute;
    right: 2.00rem;
    color: #e51a19;
}
.sub-btn {
    width: 1.76rem;
    height: 1.06rem;
    background-color: #dee2de;  /*#8e8561*/
    border: none;
    position: absolute;
    right: 0;
    color: #ffffff;
    font-size: 0.24rem;
}
.green {
     background-color: #8e8561;
}


/* 字体大小 */
.cd-f1 {
    font-size: 0.32rem;         /* 32/640 */
}
.cd-f2 {
    font-size: 0.3rem;          /* 30/640 */
}
.cd-f3 {
    font-size: 0.28rem;         /* 28/640 */
}
.cd-f4 {
    font-size: 0.26rem;         /* 26/640 */
}
.cd-f5 {
    font-size: 0.24rem;         /* 24/640 */
}
.cd-f6 {
    font-size: 0.22rem;         /* 22/640 */
}
.cd-fmin {
    font-size: 0.20rem;
}

/* 颜色 */
.answer-right {
    background-color: #003814;
}
.answer-wrong {
    background-color: #570100;
}
.answer-no-choice {
    background-color: #929292;
}
.color-base {
    color: #bfa355;
}

/* button */
.ql-btn {
    display: block;
    width: 1.46rem;
    height: 0.44rem;
    line-height: 0.44rem;
    font-size: 0.24rem;
    margin-left: 0.4rem;
    text-align: center;
    border-radius: 0.04rem;
    /* border: 0.01rem solid #f2f2f2; */
    background-color: transparent;
    border: none;
    outline: none;
}
.ql-btn:focus {
    color: #adaaaa;
}
.ql-btn-default {
    color: #fff;
    border: none;
    /* background-color: #bfa355; */
    background-color: #564932;
}

/* radio & checkbox */
.ql-ipt input[type='radio'], .ql-ipt input[type='checkbox'] {
    position: absolute;
    left: -555em;
}
.ql-ipt input[type='radio'] + i, .ql-ipt input[type='checkbox'] + i {
    display: inline;
    float: left;
    width: 0.38rem;
    height: 0.38rem;
    background: url('../../assets/images/icon_input.png') no-repeat;
    background-size: auto 0.38rem;
    background-position: -0.39rem 0;
}
.ql-ipt input[type='radio']:checked + i,
.ql-ipt input[type='checkbox']:checked + i {
    /* background-color: #8e8561;; */
    background-position: 0 0;
}


</style>

3. jquery构建方法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容