软件开发定制简易购物车实现

文章目录

一、前言

环境:VScode+Chrome
技术栈:HTML+CSS+Vue(软件开发定制组件之前的知识运用—Vue基础语法)
软件开发定制将购物车实现分成三部软件开发定制分分别实现:
第一部分:软件开发定制简单购物车功能实现;
第二部分:软件开发定制将商品序号改为勾选框;
第三部分:软件开发定制添加商店对商品进行分类。

二、第一部分

软件开发定制页面效果图:
思路:
软件开发定制分为两部分,软件开发定制上半部分用于添加商品到购物车;软件开发定制下半部分用于展示购物车详情:
1、软件开发定制先把界面的框架(ui效果),软件开发定制大致画出来—这里使用table标签
2、软件开发定制先完成下半部分的逻辑
①循环数组:软件开发定制书籍名单是从服务器传来的,所以用for软件开发定制循环遍历获得;
②软件开发定制格式化价格:实现价格¥xx.00软件开发定制的表示方法(有两种);
③完成 + 和 – 按钮:软件开发定制购买数量的±软件开发定制按钮功能通过点击事件写js实现(注意传入index软件开发定制值知道是哪一行书籍)软件开发定制并且使用按钮的disabled功能使<=1软件开发定制时不能再点(软件开发定制解决会为负数的小bug);
④加移除:软件开发定制移除功能使用splice函数,且用ifelse判断当购物车为空时显示购物车为空;
⑤算总价:书籍总价格通过计算属性实时计算获得,最后返回一个值,通过第二步的过滤器实现最后的样子;

2、完成上半部分逻辑
①v-model绑定每个表单:在点击添加按钮时,要判断每个表单是否为空,有一个表单为空则提示请输入xx内容,然后return false;
②添加至购物车的逻辑:点击添加按钮,商品添加至购物车,并清空此时上半部分的input内容

三、第二部分

页面效果图:

1、把购物车的序列号,改为勾选框,当勾选起来的时候,才会计算总价;默认不勾选;列头有全选勾选框,可以实现全选功能。
2、添加商品的时候,增加判断,如果新增商品ID已经在购物车中,那么这个时候应该是把对应商品的数量增加;否则在购物车中新增商品行。

四、第三部分

页面效果图:

1、每个商品都有对应的商店:在data中用二维数组存放商品数据
(1)“添加要购买商品” 新增2个输入框,商店后台编号和商店名称。
(2)“购物车”按商店先划分,再按商品划分。

(3) 同样需要勾选框。这里的勾选框有3种:
a.全选勾选框,b.某个商店全选勾选框,c.某个商品的勾选框。勾选上的才算总价。默认不勾选。
大概属性定义思路:checkbox的属性是一个布尔属性,用v-model双向绑定一个布尔属性,即可在方法中用来实现各种功能;
这里分成三种复选框,一是isAllChecked(代表全选复选框,决定商店商品所有复选框的状态);二是isStChecked(代表商店复选框,决定某商店下所有商品的复选框状态);三是isChecked(代表商品复选框,决定该商品复选框的状态)

大概功能实现思路:
①先实现全选复选框(商店复选框)让下面所有商品复选框选中和取消选中
思路:让下面所有复选框的checked属性(选中状态) 跟随 全选复选框(商店复选框)即可

②下面商品复选框需要全部选中,全选复选框(商店复选框)才会选中做法:每次点击,都要循环查看下面所有的复选框是否有没选中的,如果有一个没选中的, 上面就不选中。

(4) 同样添加商品的时候要加上判断。分3种情况:
a.新增商品已经在购物车中有了,则该商品数量增加;
b.新增商品不在购物车中,但是其对应的商店在购物车中,则在商店后面新增该商品;
c.新增商品不在购物车中,且对应商店也不在购物车中,新增商店和商品。
(可看问题总结5)

2、页面结构:
页面结构实现使用二维数组来实现商店商品,因为这里使用的是table来做,我的思路是之前的thead不变,对tbody进行更改:
在tbody中再嵌入一个table-外层for循环商店,在table中再分为thead和tbody,tbody的tr再内层for循环商店下的商品即可实现上面效果图。
注意:在table标签中进行v-if判断该商店是否有商品,没有则不显示该商店,另外,这里不显示商品并没有删除存进data中的商店的数据,要在每次对商品进行移除时判断该商店商品是否为空,为空则用splice对该商店数据进行删除。

五、问题总结


这里报错的原因是:

细节问题,Price的input框为text,导致数据类型是字符串,所以报错;将数据类型转换成数字类型的就不会报这个错了;
解决方法:
①在JS中将return ‘¥’ + price.toFixed(2); 改成 return '¥ ’ + parseFloat(val).toFixed(2);
②在html中利用v-model的number修饰符,即v-model.number = “good.price”
2.注意不能直接进行this.goods.push(this.good);.这个方法会把good的地址也push进去,而不是拷贝;要构建一个新对象,再push进去
// (parse必须是json格式,所以先用stringify转换成json字符串类型再用parse转换成对象)
let goodJson = JSON.stringify(this.good);
let addGood = JSON.parse(goodJson);
this.goods.push(addGood);

3.按钮的全选和取消全选
大概属性定义思路:checkbox的属性是一个布尔属性,用v-model双向绑定一个布尔属性,即可在方法中用来实现各种功能;
这里分成三种复选框,一是isAllChecked(代表全选复选框,决定商店商品所有复选框的状态);二是isStChecked(代表商店复选框,决定某商店下所有商品的复选框状态);三是isChecked(代表商品复选框,决定该商品复选框的状态)

大概功能实现思路:
①先实现全选复选框(商店复选框)让下面所有商品复选框选中和取消选中
思路:让下面所有复选框的checked属性(选中状态) 跟随 全选复选框(商店复选框)即可

②下面商品复选框需要全部选中,全选复选框(商店复选框)才会选中做法:每次点击,都要循环查看下面所有的复选框是否有没选中的,如果有一个没选中的, 上面就不选中。

4.在实现当添加的商品编号已经在购物车存在,进行增加购物车商品数量的功能时:
1)我在对购物车商品编号遍历对比的时候用‘ ===’ 等同符时,两边值类型不相等,但是我分别打印后得到的都是number类型,不知道什么原因;所以改为使用等值符,只对值进行比较。

2)/对购物车的商品进行遍历,如果新加入的商品编号已存在就直接进行商品数量增加,否则直接进行push ,有两种实现方法:
①使用flag判断是否进行了数量增加的操作,当进行了购物车商品数量增加时,flag=false,就不会执行push操作;(不推荐此方法,在加入商店对商品进行分类后,此方法不好写)

②直接return,当进行了购物车商品数量增加时,return;此操作return接下来的所有代码都不会执行(推荐此方法,方便又快捷)

1)当商店存在,但是商品不存在,在该商店下新增商品时,新增商品addGood的类型与goods类型不同,所以需要再次构造新增对象addG,使addG的类型与goods相同,然后再在该商店下进行push

2)当商店商品不存在购物车时,要先创建商店,然后再在商店下创建商品,一样类型要一致

六、核心代码

html:

 <div id="app">    <div class="add">      <h3>添加要购买的商品:</h3>      <table>        <tr>          <td>商店后台编号:</td>          <td><input type="text" placeholder="请填写商店编号" v-model="good.storeId"></td>        </tr>        <tr>          <td>商店名称:</td>          <td><input type="text" placeholder="请填写商店名称" v-model="good.storeName"></td>        </tr>        <tr>          <td>商品后台编号:</td>          <td><input type="text" placeholder="请填写商品编号" v-model="good.id"></td>        </tr>        <tr>          <td>商品名称:</td>          <td><input type="text" placeholder="请填写商品名称" v-model="good.name"></td>        </tr>        <tr>          <td>商品价格:</td>          <td><input type="text" placeholder="请填写商品价格" v-model="good.price"></td>        </tr>        <tr>          <td>商品数量:</td>          <td><input type="text" placeholder="请填写商品数量" v-model.number="good.count"></td>        </tr>        <tr>          <td colspan="2"><button @click="addToCar()">添加</button></td>        </tr>      </table>    </div>    <!-- 当购物车没有商店时,意味着没有商品,那么就显示购物车为空 -->    <div v-if="infos.length">      <h3 >购物车:</h3>      <table>        <thead>          <tr>            <th class="weightSmall"><input type="checkbox" v-model="isAllChecked" @click="clickAllChecked"></th>            <th class="weightBig">书籍名称</th>            <th class="weightMid">价格</th>            <th class="weightMid">购买数量</th>            <th class="weightMid">操作</th>          </tr>        </thead>        <tbody>          <!-- 外层for循环商店,如果该商店无商品,则不显示 -->          <table v-for="(items, indexs) in infos" v-if="infos[indexs].goods.length">            <thead>              <th colspan="5"><input type="checkbox" v-model="items.isStChecked" @click="clickStChecked(indexs)">{{items.storeName}}</th>            </thead>            <tbody>              <!-- 内层for循环商店下的商品 -->              <tr v-for="(item, index) in items.goods">                <td class="weightSmall"><input type="checkbox" v-model="item.isChecked" @click="clickChecked(indexs,index)"></td>                <td class="weightBig">{{item.name}}</td>                <td class="weightMid">{{item.price | getFinalPrice}}</td>                <td class="weightMid">                  <button @click="decrement(indexs,index)" :disabled="item.count <= 1">-</button>                  {{item.count}}                  <button @click="increment(indexs,index)">+</button>                </td>                <td class="weightMid">                  <!-- 每次移除商品时判断该商店商品是否为空,为空就删除该商店 -->                  <button @click="removeHandle(indexs,index)" >移除</button>                </td>              </tr>            </tbody>          </table>          <table>            <tr>            <td class="final">总价格:{{totalPrice | getFinalPrice}}</td>            </tr>          </table>        </tbody>      </table>          </div>    <h2 v-else>购物车为空</h2>  </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

JS:

const app = new Vue({  el: '#app',  data: {    // 创建一个对象用于存放要添加的商品信息    good: {      storeId: '',      storeName: '',      id: '',      name: '',      price: '',      count: '',    },    //checkbox用布尔值表示是否选中,在data里绑定该属性,然后每次点击对该属性进行操作    isAllChecked: false,    infos: [      {        storeId: 1,        storeName: '华为手机店',        isStChecked: false,        goods: [          {            id: 1,            name: '华为手机',            price: 2000,            count: 1,            isChecked: false,          },          {            id: 2,            name: '华为Mate30手机',            price: 5000,            count: 1,            isChecked: false,          },        ]      },      {        storeId: 2,        storeName: '体育用品店',        isStChecked: false,        goods: [          {            id: 3,            name: '篮球',            price: 200,            count: 1,            isChecked: false,          },        ]      },      {        storeId: 3,        storeName: '手机用品店',        isStChecked: false,        goods: [          {            id: 4,            name: '手机膜',            price: 30,            count: 1,            isChecked: false,          },        ]      }    ],  },  methods: {    // 方法①调用时用getFinalPrice(item.price)    // getFinalPrice(price) {    //   return '¥' + price.toFixed(2);    // },    decrement(indexs, index) {      this.infos[indexs].goods[index].count--;    },    increment(indexs, index) {      this.infos[indexs].goods[index].count++;    },    removeHandle(indexs, index) {      this.infos[indexs].goods.splice(index, 1);      if (this.infos[indexs].goods.length === 0) {        this.infos.splice(indexs, 1);      }    },    // 二、添加到购物车的功能    addToCar() {      //如果有一个表单元素输入空,就返回空值,不会在进行在购物车添加的操作      if (!this.judgeGood()) {        return;      }      else {        //对购物车的商品进行遍历,有三种情况:        for (let j = 0; j < this.infos.length; j++) {          if (this.good.storeId == this.infos[j].storeId) {            for (let i = 0; i < this.infos[j].goods.length; i++) {              //a  商店存在且新增商品在购物车中存在,商品数量增加;              if (this.good.id == this.infos[j].goods[i].id) {                this.infos[j].goods[i].count += this.good.count;                this.clearGood();                return;              }            }            //b  商店存在但新增商品不在购物车中,则在该商店下push新增商品;            //先构造新增的对象            let goodJson = JSON.stringify(this.good);            let addGood = JSON.parse(goodJson);            let addG = {              id: addGood.id,              name: addGood.name,              price: addGood.price,              count: addGood.count,              isChecked: false,            };            this.infos[j].goods.push(addG);            this.clearGood();          }        }        /*1)这个方法会把good的地址也push进去,而不是拷贝        this.goods.push(this.good);        2)构建一个新对象,再push进去        (parse必须是json格式,所以先用stringify转换成json字符串类型再用parse转换成对象)*/        //c   商店不存在且新增商品不在购物车中,则新增商店商品        //先构造新增的对象        let goodJson = JSON.stringify(this.good);        let addGood = JSON.parse(goodJson);        let addS = {          storeId: addGood.storeId,          storeName: addGood.storeName,          isStChecked: false,          goods: [],        };        let addG = {          id: addGood.id,          name: addGood.name,          price: addGood.price,          count: addGood.count,          isChecked: false,        };        this.infos.push(addS);        addS.goods.push(addG);        this.clearGood();      }    },    //判断每个输入框的内容是否输入,让表单每个元素必填    judgeGood() {      if (this.good.storeId == '' || this.good.storeId == undefined || this.good.storeId == null) {        alert('请输入商店后台编号');        return false;      };      if (this.good.storeName == '' || this.good.storeName == undefined || this.good.storeName == null) {        alert('请输入商店名称');        return false;      };      if (this.good.id == '' || this.good.id == undefined || this.good.id == null) {        alert('请输入商品编号');        return false;      };      if (this.good.name == '' || this.good.name == undefined || this.good.name == null) {        alert('请输入商品名称');        return false;      };      if (this.good.price == '' || this.good.price == undefined || this.good.price == null) {        alert('请输入商品价格');        return false;      };      if (this.good.count == '' || this.good.count == undefined || this.good.count == null) {        alert('请输入商品数量');        return false;      };      return true;    },    //当点击添加时,输入框内的内容同时为空    clearGood() {      this.good.storeId = '';      this.good.storeName = '';      this.good.id = '';      this.good.name = '';      this.good.price = '';      this.good.count = '';    },    // 1. 全选复选框选中,让所有商店所有商品被选中    clickAllChecked() {      let afterClickChecked = !this.isAllChecked;      for (let i = 0; i < this.infos.length; i++) {        this.infos[i].isStChecked = afterClickChecked;        for (let j = 0; j < this.infos[i].goods.length; j++) {          this.infos[i].goods[j].isChecked = afterClickChecked;        }      }    },    // 2.点击商店复选框,该商店下面所有商品的复选框被选中    clickStChecked(indexs) {      this.infos[indexs].isStChecked = !this.infos[indexs].isStChecked;//没有这句,4运行不起作用,因为商店isStChecked没有被更改      let afterClickChecked = this.infos[indexs].isStChecked;      for (let i = 0; i < this.infos[indexs].goods.length; i++) {        this.infos[indexs].goods[i].isChecked = afterClickChecked;      }      //4.解决3c中的小bug,如果点击了商店复选框,就调用此方法对商店进行循环判断      let flagSt = true;      for (let j = 0; j < this.infos.length; j++) {        if (!this.infos[j].isStChecked) {          flagSt = false;          break;        }      }      this.isAllChecked = flagSt;    },    //3.    //a.每次点击商品复选框,都循环查看该商店下所有商品复选框是否全部选中,只要有一个商品没选中,商店就不会被选中;    //b.同时,也循环查看商店的复选框是否全部选中,商店复选框全选中,则全选复选框选中    /*c.另外有个小bug,如果所有商店的复选框已全部选中,但最后一次点击的复选框不是商品复选框,全选复选框不会被选中    因为如果最后一次的点击后,所有商店商品被选中,但点击的不是商品复选框,则不会调用此方法(判断商店是否全部选中的循环没有执行)*/    clickChecked(indexs, index) {      //决定商店复选框是否选中      let flag = true;      this.infos[indexs].goods[index].isChecked = !this.infos[indexs].goods[index].isChecked;      for (let i = 0; i < this.infos[indexs].goods.length; i++) {        if (!this.infos[indexs].goods[i].isChecked) {          flag = false;          break;        }      }      this.infos[indexs].isStChecked = flag;      //决定全选复选框是否选中      let flagSt = true;      for (let j = 0; j < this.infos.length; j++) {        if (!this.infos[j].isStChecked) {          flagSt = false;          break;        }      }      this.isAllChecked = flagSt;    },  },  computed: {    totalPrice() {      let totalPrice = 0;      for (let i = 0; i < this.infos.length; i++) {        for (let j = 0; j < this.infos[i].goods.length; j++) {          //被选中的商品才会把其价格加入总价格中          if (this.infos[i].goods[j].isChecked) {            totalPrice += this.infos[i].goods[j].price * this.infos[i].goods[j].count;          }        }      }      return totalPrice;    }  },  filters: {    // 方法②调用时用item.price | getFinalPrice    getFinalPrice(price) {      return '¥' + parseFloat(price).toFixed(2);    },  }});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259

以上是我学习Vue的阶段性练习案例,如有不足,欢迎提出指正以及互相学习交流。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发