vuejs手把手教你写一个完整的购物车实例代码


Posted in Javascript onJuly 06, 2017

由于我们公司是主营业务是海淘,所以每个项目都是类似淘宝天猫之类的商城,那么购物车就是一个重点开发功能模块。介于之前我都是用jq来写购物车的,这次就用vuejs来写一个购物车。下面我就从全选,数量控制器,运费,商品金额计算等方法来演示一下一个能用在实际场景的购物车是怎么做出来的以及记录一下这次用vuejs踩过的坑。

1.一层数据结构-全选

下面这段代码和vuejs官网里面checkbox绑定很像。不明白的可以直接上vuejs官网看看。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs-全选</title>
<style type="text/css">
* {
  padding: 0;
  margin: 0;
}
a {
  color: #333;
  text-decoration:none;
}
</style>
</head>
<body>
<label>
  <input type="checkbox" name="all" v-on:click="chooseAll" v-model="selectArr.length==goodsList.length" />
  <span>全选</span>
</label>
<div v-for="(index, item) in goodsList">
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >
    <input type="checkbox" :value="index" v-model="selectArr" />
    商品名称:<span v-html="item.name"></span> |
    价格:<span v-html="item.price"></span>
  </a>
</div>
<label>
  <input type="checkbox" name="all" v-on:click="chooseAll" v-model="selectArr.length==goodsList.length" />
  <span>全选</span>
</label>
<script src="http://cdn.bootcss.com/vue/1.0.7/vue.js"></script>
<script>
var vue = new Vue({
  el : 'body',
  data : {
    goodsList : [
      {
        name : '山本汉方1',
        price : '19.00'
      },
      {
        name : '山本汉方2',
        price : '19.00'
      },
      {
        name : '山本汉方3',
        price : '19.00'
      },
      {
        name : '山本汉方4',
        price : '19.00'
      },
      {
        name : '山本汉方5',
        price : '19.00'
      },
    ],
    selectArr : []
  },
  ready : function() {},
  methods : {
    chooseAll : function(event) {
      var oThis = this;
      oThis.selectArr = [];
      if ( event.currentTarget.checked ) {
        oThis.goodsList.forEach(function(item , index) {
          oThis.selectArr.push(index);
        });
      }
      console.log(oThis.selectArr);
    }
  }
})
</script>
</body>
</html>

2.二层数据结构-全选

一层数据结构的购物车在现实中是很少看到的,比如我们最熟悉的淘宝购物车是按照店铺分的,那么必然是多层的数据结构。这次在写这个二层数据接口的全选,碰到一个很大的坑,一开始我是用了一层数据结构的数据,发现当对象数组里面的某个值改变了,视图竟然没有触发!,所以会造成下面所有的checkbox都被选中了,最上面的那个全选checkbox竟然还是没有被选中。感觉告诉我这是vuejs的坑,后来发现是js的坑。具体可以看这个。方法是百度到了,可是放我这里没有用(应该是版本问题)。于是我就改了数据结构。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs-全选</title>
<style type="text/css">
* {
  padding: 0;
  margin: 0;
}
a {
  color: #333;
  text-decoration:none;
}
.goods-item {
  display: block;
}
.store-item {
  margin-bottom: 20px;
}
</style>
</head>
<body>
<div v-for="(index1, item) in goodsObj" class="store-item">
  <p>
    <span v-html="item.name"></span>
    <label>
      <input type="checkbox" name="all" v-on:click="chooseShopGoods(index1)" v-model="item.checked" />
      <span>全选</span>
    </label>
  </p>
  <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" v-for="(index, data) in item.list" class="goods-item">
    <input type="checkbox" v-model="data.checked" v-on:click="choose(index1, index)" />
    商品名称:<span v-html="data.name"></span> |
    价格:<span v-html="data.price"></span>
  </a>
</div>
<label>
  <input type="checkbox" name="all" v-on:click="chooseAllGoods()" v-model="allChecked" />
  <span>全选</span>
</label>
<script src="http://cdn.bootcss.com/vue/1.0.7/vue.js"></script>
<script>
var goodsObj = [
  {
    name : '大胖的店',
    checked : false,
    list : [
      {
        name : '麻辣二胖',
        price : 23.00,
        realStock : 10,
        fare : 1.5,
        num : 1,
        checked : false,
      },

      {
        name : '香辣二胖',
        price : 21.00,
        realStock : 2,
        fare : 1.5,
        num : 2,
        checked : false,
      },

      {
        name : '红烧二胖',
        price : 88.00,
        realStock : 8,
        fare : 1.5,
        num : 4,
        checked : false,
      }
    ]
  },

  {
    name : '二胖的店',
    checked : false,
    list : [
      {
        name : '漂亮的裙子',
        price : 166.00,
        realStock : 10,
        fare : 2,
        num : 1,
        checked : false,
      },

      {
        name : '漂亮的短袖',
        price : 188.00,
        realStock : 2,
        fare : 1.5,
        num : 2,
        checked : false,
      },

      {
        name : '漂亮的鞋子',
        price : 299.00,
        realStock : 1,
        fare : 3,
        num : 1,
        checked : false,
      }
    ]
  },

  {
    name : '胖胖的店',
    checked : false,
    list : [
      {
        name : '福满多',
        price : 3.00,
        realStock : 10,
        fare : .5,
        num : 10,
        checked : false,
      },

      {
        name : '精品卫龙',
        price : 1.50,
        realStock : 2,
        fare : 2,
        num : 2,
        checked : false,
      },

      {
        name : '周长江',
        price : 2.50,
        realStock : 3,
        fare : 5,
        num : 2,
        checked : false,
      }
    ]
  },
];
var vue = new Vue({
  el : 'body',
  data : {
    goodsObj : goodsObj,
    allChecked : false
  },
  ready : function() {

  },
  methods : {
    // 全部商品全选
    chooseAllGoods : function() {
      var flag = true;
      if ( this.allChecked ) {
        flag = false;
      }
      for ( var i = 0, len = this.goodsObj.length; i < len; i++ ) {
        this.goodsObj[i]['checked'] = flag;
        var list = this.goodsObj[i]['list'];
        for ( var k = 0, len1 = list.length; k < len1; k++ ) {
          list[k]['checked'] = flag;
        }
      }
      this.allChecked = !this.allChecked;
    },

    // 每个店铺全选
    chooseShopGoods : function( index) {
      var list = this.goodsObj[index]['list'],
        len = list.length;
      if ( this.goodsObj[index]['checked'] ) {
        for (var i = 0; i < len; i++ ) {
          list[i]['checked'] = false;
        }
      } else {
        for (var i = 0; i < len; i++ ) {
          list[i]['checked'] = true;
        }
      }
      this.goodsObj[index]['checked'] = !this.goodsObj[index]['checked'];

      // 判断是否选择所有商品的全选
      this.isChooseAll();
    },

    // 单个选择
    choose : function( index1, index) {
      var list = this.goodsObj[index1]['list'],
        len = list.length;
      if ( list[index]['checked'] ) {
        this.goodsObj[index1]['checked'] = false;
        this.allChecked = false;
        list[index]['checked'] = !list[index]['checked'];
      } else {
        list[index]['checked'] = !list[index]['checked'];

        // 判断是否选择当前店铺的全选
        var flag = true;
        for (var i = 0; i < len; i++ ) {
          if ( list[i]['checked'] == false ) {
            flag = false;
            break;
          }
        }
        flag == true ? this.goodsObj[index1]['checked'] = true : this.goodsObj[index1]['checked'] = false;
      }

      // 判断是否选择所有商品的全选
      this.isChooseAll();
    },

    // 判断是否选择所有商品的全选
    isChooseAll : function() {
      var flag1 = true;
      for ( var i = 0, len = this.goodsObj.length; i < len; i++ ) {
        if ( this.goodsObj[i]['checked'] == false ) {
          flag1 = false;
          break;
        }
      }
      flag1 == true ? this.allChecked = true : this.allChecked = false;
    },

  }
})
</script>
</body>
</html>

3.一层数据结构-数量选择器

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs-数量选择器(1层数据结构)</title>
<style type="text/css">
*{
  padding:0;
  margin: 0;
  box-sizing: border-box;
  font-size: 16px;
}
.clearfix:after {
  content: ".";
  visibility: hidden;
  display: block;
  height: .1px;
  font-size: .1em;
  line-height: 0;
  clear: both;
}
.quantity-selector {
  margin-bottom: 20px;
  width: 8.571rem;
  line-height: 2.857rem;
  border: 1px solid #d1d6e4;
  border-radius: 3px;
}
.quantity-selector .reduce, 
.quantity-selector .add {
  float: left;
  width: 33.33%;
  border-right: 1px solid #d1d6e4;
  text-align: center;
  cursor: pointer;
}
.quantity-selector .number {
  float: left;
  width: 33.33%;
  height: 2.857rem;
  padding: .5rem 0;
  line-height: 1rem;
  border: none;
  text-align: center;
}
.quantity-selector .add {
  border-left: 1px solid #d1d6e4;
  border-right: none;
}
.quantity-selector .disable {
  color: #d2d2d2;
  cursor: default;
}
</style>
</head>
<body>

<div v-for="data in goodsList">
  <p>商品数量 :<span v-html="data.num"></span></p>
  <p>商品库存 :<span v-html="data.realStock"></span></p>
  <div class="quantity-selector clearfix">
    <span class="reduce" v-on:click="numChange($index, -1)" v-bind:class="{ 'disable' : data.num==1 }">-</span>
    <input type="number" v-bind:value="data.num" class="number" v-bind:data-realStock="data.realStock" v-on:keyUp="numEntry($index)" v-on:keyDown="numEntry($index)" v-model="data.num"/>
    <span class="add" v-on:click="numChange($index, 1)" v-bind:class="{ 'disable' : data.num==data.realStock }">+</span>
  </div>
</div>

<script src="http://cdn.bootcss.com/vue/1.0.7/vue.js"></script>
<script>
var vue = new Vue({
  el : 'body',
  data : {
    goodsList : [
      {
        name : '山本汉方1',
        price : '19.00',
        realStock : 10,
        num : 1
      },
      {
        name : '山本汉方1',
        price : '19.00',
        realStock : 7,
        num : 8
      },
      {
        name : '山本汉方1',
        price : '19.00',
        realStock : 2,
        num : 2
      },
    ]
  },
  ready : function() {},
  methods : {
    numChange : function(index, numChange) {
      var goods = this.goodsList[index];
      if ( numChange == 1 ) {
        goods.num++;
      } else if ( numChange == -1 ) {
        goods.num--;
      }

      if ( goods.num <= 1 ) {
        goods.num = 1;
      } 

      if ( goods.num >= goods.realStock ) {
        goods.num = goods.realStock;
      }
    },

    numEntry : function(index) {
      var goods = this.goodsList[index];
      if ( goods.num <=1 ) {
        goods.num = 1;
      }

      if ( goods.num > goods.realStock ) {
        goods.num = goods.realStock;
      }

    }
    
  }
})
</script>
</body>
</html>

4.二层数据结构-数据选择器

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs-数量选择器(2层数据结构)</title>
<style type="text/css">
*{
  padding:0;
  margin: 0;
  box-sizing: border-box;
  font-size: 16px;
}
a {
  text-decoration: none;
  color: #333;
}
.clearfix:after {
  content: ".";
  visibility: hidden;
  display: block;
  height: .1px;
  font-size: .1em;
  line-height: 0;
  clear: both;
}
.quantity-selector {
  margin: 0 auto;
  width: 8.571rem;
  line-height: 30px;
  border: 1px solid #d1d6e4;
  border-radius: 3px;
}
.quantity-selector .reduce, 
.quantity-selector .add {
  float: left;
  width: 33.33%;
  border-right: 1px solid #d1d6e4;
  text-align: center;
  cursor: pointer;
}
.quantity-selector .number {
  float: left;
  width: 33.33%;
  height: 30px;
  border: none;
  padding-left: 10px;
  text-align: center;
}
.quantity-selector .add {
  border-left: 1px solid #d1d6e4;
  border-right: none;
}
.quantity-selector .disable {
  color: #d2d2d2;
  cursor: default;
}

/*店铺开始*/
.store-item {
  width: 600px;
  margin: 30px auto;
}
.store-item th {
  height: 40px;
  background: #d2d2d2;
  -webkit-text-stroke: 1px #ff7500;
  font-size: 18px;
}
.store-item td {
  height: 60px;
  text-align: center;
}
.cal-store-box {
  text-align: right;
}
.store-footer {
  width: 600px;
  margin: 50px auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
/*店铺结束*/
</style>
</head>
<body>
<div class="store-item" v-for="(index1, item) in goodsObj"> 
  <p v-html="index1"></p>
  <table class="store-item">
    <col width="10%"></col>
    <col width="10%"></col>
    <col width="20%"></col>
    <col width="10%"></col>
    <col width="40%"></col>
    <col width="10%"></col>
    <thead class="thead">
      <tr>
        <th>选择</th>
        <th>商品</th>
        <th>单价</th>
        <th>运费</th>
        <th>数量</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(index, data) in item">
        <td>
          
        </td>
        <td>
          <p><span v-html="data.name"></span></p>
        </td>
        <td v-html="(data.price).toFixed(2)"></td>
        <td v-html="(data.fare).toFixed(2)"></td>
        <td>
          <div class="quantity-selector clearfix">
            <span class="reduce" v-on:click="numChange(index1, $index, -1)" v-bind:class="{ 'disable' : data.num==1 }">-</span>
            <input type="number" v-bind:value="data.num" class="number" v-bind:data-realStock="data.realStock" v-on:keyUp="numEntry(index1, $index)" v-on:keyDown="numEntry(index1, $index)" v-model="data.num"/>
            <span class="add" v-on:click="numChange(index1, $index, 1)" v-bind:class="{ 'disable' : data.num==data.realStock }">+</span>
          </div>
        </td>
        <td>
          <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >删除</a>
        </td>
      </tr>
    </tbody>
  </table>
  <div class="cal-store-box">
    <p>店铺总运费: <span v-html="calEveryFare(index1)"></span></p>
    <p>店铺商品总金额: <span v-html="calEveryStore(index1)"></span></p>
  </div>
</div>

<div class="store-footer">
  <!-- <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >
    <input type="checkbox" />
    <span>全选</span>
  </a> -->
  <div class="cal-box">
    <p>商品总金额:<span v-html="totalFare"></span></p>
    <p>运费总金额:<span v-html="totalMoney"></span></p>
  </div>
</div>

<script src="http://cdn.bootcss.com/vue/1.0.7/vue.js"></script>
<script>
var goodsObj = {
  '大胖的店' : [
    {
      name : '康师傅',
      price : 23.00,
      realStock : 10,
      fare : 1.5,
      num : 1
    },

    {
      name : '今麦郎',
      price : 26.00,
      realStock : 2,
      fare : 1.5,
      num : 2
    },

    {
      name : '比巴卜',
      price : 88.00,
      realStock : 8,
      fare : 1.5,
      num : 4
    }
  ],

  '二胖的店' : [
    {
      name : '好看的鞋子',
      price : 23.00,
      realStock : 7,
      fare : 2,
      num : 1
    },

    {
      name : '好看的裙子',
      price : 26.00,
      realStock : 5,
      fare : 2,
      num : 5
    },

    {
      name : '好看的短袖',
      price : 88.00,
      realStock : 10,
      fare : 2,
      num : 1
    }
  ],

  '胖胖的店' : [
    {
      name : '福满多1号',
      price : 26.00,
      realStock : 7,
      fare : 3,
      num : 1
    },

    {
      name : '福满多2号',
      price : 26.00,
      realStock : 7,
      fare : 3,
      num : 1
    },

    {
      name : '经典卫龙辣条',
      price : 16.00,
      realStock : 50,
      fare : 3,
      num : 5
    },

    {
      name : '霸王牛津',
      price : 80.00,
      realStock : 10,
      fare : 3,
      num : 6
    }
  ]
};
var vue = new Vue({
  el : 'body',
  data : {
    goodsObj : goodsObj,
    totalMoney : 0,
    totalFare : 0
  },
  ready : function() {
    this.calTotalMoney();
    this.calTotalFare();
  },
  methods : {
    numChange : function(index1, index, numChange) {
      var goods = this.goodsObj[index1][index],
        oThis = this;
      if ( numChange == 1 ) {
        goods.num++;
      } else if ( numChange == -1 ) {
        goods.num--;
      }

      if ( goods.num <= 1 ) {
        goods.num = 1;
      } 

      if ( goods.num >= goods.realStock ) {
        goods.num = goods.realStock;
      }
      this.calTotalMoney();
    },

    numEntry : function(index1, index) {
      var goods = this.goodsObj[index1][index];
      if ( goods.num <=1 ) {
        goods.num = 1;
      }

      if ( goods.num > goods.realStock ) {
        goods.num = goods.realStock;
      }
      this.calTotalMoney();
    },

    calEveryStore : function(index) {
      var everyStoreMoney = 0;
      this.goodsObj[index].forEach(function(item, index, arr) {
        everyStoreMoney += parseFloat(item.price) * parseFloat(item.num);
      });
      return everyStoreMoney.toFixed(2);
    },

    calEveryFare : function(index) {
      var everyStoreFare = 0;
      this.goodsObj[index].forEach(function(item, index, arr) {
        everyStoreFare += parseFloat(item.fare) * parseFloat(item.num);
      });
      return everyStoreFare.toFixed(2);
    },

    calTotalMoney : function () {
      var oThis = this;
      this.totalMoney = 0;
      for ( var x in this.goodsObj ) {
        this.goodsObj[x].forEach(function(item, index, arr) {
          oThis.totalMoney += parseFloat(item.price) * parseFloat(item.num);
        });
      }
      this.totalMoney = this.totalMoney.toFixed(2);
    },

    calTotalFare : function () {
      var oThis = this;
      this.totalFare = 0;
      for ( var x in this.goodsObj ) {
        this.goodsObj[x].forEach(function(item, index, arr) {
          oThis.totalFare += parseFloat(item.fare) * parseFloat(item.num);
        });
      }
      this.totalFare = this.totalFare.toFixed(2);
    },
    
  }
})
</script>
</body>
</html>

5.一个完整的购物车

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs-数量选择器(2层数据结构)</title>
<style type="text/css">
*{
  padding:0;
  margin: 0;
  box-sizing: border-box;
  font-size: 16px;
}
a {
  text-decoration: none;
  color: #333;
}
.clearfix:after {
  content: ".";
  visibility: hidden;
  display: block;
  height: .1px;
  font-size: .1em;
  line-height: 0;
  clear: both;
}
.quantity-selector {
  margin: 0 auto;
  width: 8.571rem;
  line-height: 30px;
  border: 1px solid #d1d6e4;
  border-radius: 3px;
}
.quantity-selector .reduce, 
.quantity-selector .add {
  float: left;
  width: 33.33%;
  border-right: 1px solid #d1d6e4;
  text-align: center;
  cursor: pointer;
}
.quantity-selector .number {
  float: left;
  width: 33.33%;
  height: 30px;
  border: none;
  padding-left: 10px;
  text-align: center;
}
.quantity-selector .add {
  border-left: 1px solid #d1d6e4;
  border-right: none;
}
.quantity-selector .disable {
  color: #d2d2d2;
  cursor: default;
}

label {
  cursor: pointer;
}

.choose-all {
  margin-left: 20px;
}

/*店铺开始*/
.store-item {
  width: 600px;
  margin: 30px auto;
}
.store-item th {
  height: 40px;
  background: #d2d2d2;
  -webkit-text-stroke: 1px #ff7500;
  font-size: 18px;
}
.store-item td {
  height: 60px;
  text-align: center;
}
.cal-store-box {
  text-align: right;
}
.store-footer {
  width: 600px;
  margin: 50px auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
/*店铺结束*/
</style>
</head>
<body>
<div class="store-item" v-for="(index1, item) in goodsObj"> 
  <p>
    <span v-html="item.name"></span>
    <label class="choose-all">
      <input type="checkbox" name="all" v-on:click="chooseShopGoods(index1)" v-model="item.checked" />
      <span>全选</span>
    </label>
  </p>
  <table class="store-item">
    <col width="10%"></col>
    <col width="15%"></col>
    <col width="15%"></col>
    <col width="10%"></col>
    <col width="40%"></col>
    <col width="10%"></col>
    <thead class="thead">
      <tr>
        <th>选择</th>
        <th>商品</th>
        <th>单价</th>
        <th>运费</th>
        <th>数量</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(index, data) in item.list">
        <td>
          <input type="checkbox" name="all" v-model="data.checked" v-on:click="choose(index1, index)" />
        </td>
        <td>
          <p><span v-html="data.name"></span></p>
        </td>
        <td v-html="(data.price).toFixed(2)"></td>
        <td v-html="(data.fare).toFixed(2)"></td>
        <td>
          <div class="quantity-selector clearfix">
            <span class="reduce" v-on:click="numChange(index1, $index, -1)" v-bind:class="{ 'disable' : data.num==1 }">-</span>
            <input type="number" v-bind:value="data.num" class="number" v-bind:data-realStock="data.realStock" v-on:keyUp="numEntry(index1, $index)" v-on:keyDown="numEntry(index1, $index)" v-model="data.num"/>
            <span class="add" v-on:click="numChange(index1, $index, 1)" v-bind:class="{ 'disable' : data.num==data.realStock }">+</span>
          </div>
        </td>
        <td>
          <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" v-on:click="delGoods(index1, index)">删除</a>
        </td>
      </tr>
    </tbody>
  </table>
  <div class="cal-store-box">
    <p>店铺总运费: <span v-html="calEveryFare(index1)"></span></p>
    <p>店铺商品总金额: <span v-html="calEveryStore(index1)"></span></p>
  </div>
</div>

<div class="store-footer">
  <label>
    <input type="checkbox" v-on:click="chooseAllGoods($event)" v-model="allChecked" />
    <span>全选</span>
  </label>
  <div class="cal-box">
    <p>商品总运费:<span v-html="totalFare.toFixed(2)"></span></p>
    <p>商品总金额:<span v-html="totalMoney.toFixed(2)"></span></p>
  </div>
</div>

<script src="http://cdn.bootcss.com/vue/1.0.7/vue.js"></script>
<script>
var goodsObj = [
  {
    name : '大胖的店',
    checked : false,
    list : [
      {
        name : '麻辣二胖',
        price : 23.00,
        realStock : 10,
        fare : 1.5,
        num : 1,
        checked : false,
      },

      {
        name : '香辣二胖',
        price : 21.00,
        realStock : 2,
        fare : 1.5,
        num : 2,
        checked : false,
      },

      {
        name : '红烧二胖',
        price : 88.00,
        realStock : 8,
        fare : 1.5,
        num : 4,
        checked : false,
      }
    ]
  },

  {
    name : '二胖的店',
    checked : false,
    list : [
      {
        name : '漂亮的裙子',
        price : 166.00,
        realStock : 10,
        fare : 2,
        num : 1,
        checked : false,
      },

      {
        name : '漂亮的短袖',
        price : 188.00,
        realStock : 2,
        fare : 1.5,
        num : 2,
        checked : false,
      },

      {
        name : '漂亮的鞋子',
        price : 299.00,
        realStock : 1,
        fare : 3,
        num : 1,
        checked : false,
      }
    ]
  },

  {
    name : '胖胖的店',
    checked : false,
    list : [
      {
        name : '福满多',
        price : 3.00,
        realStock : 10,
        fare : .5,
        num : 10,
        checked : false,
      },

      {
        name : '精品卫龙',
        price : 1.50,
        realStock : 2,
        fare : 2,
        num : 2,
        checked : false,
      },

      {
        name : '周长江',
        price : 2.50,
        realStock : 3,
        fare : 5,
        num : 2,
        checked : false,
      }
    ]
  },
];
var vue = new Vue({
  el : 'body',
  data : {
    goodsObj : goodsObj,
    totalMoney : 0,
    totalFare : 0,
    allChecked : false
  },
  ready : function() {},
  methods : {

    // 全部商品全选
    chooseAllGoods : function() {
      var flag = true;
      if ( this.allChecked ) {
        flag = false;
      }
      for ( var i = 0, len = this.goodsObj.length; i < len; i++ ) {
        this.goodsObj[i]['checked'] = flag;
        var list = this.goodsObj[i]['list'];
        for ( var k = 0, len1 = list.length; k < len1; k++ ) {
          list[k]['checked'] = flag;
        }
      }
      this.allChecked = !this.allChecked;
      this.calTotalMoney();
      this.calTotalFare();
    },

    // 每个店铺全选
    chooseShopGoods : function( index) {
      var list = this.goodsObj[index]['list'],
        len = list.length;
      if ( this.goodsObj[index]['checked'] ) {
        for (var i = 0; i < len; i++ ) {
          list[i]['checked'] = false;
        }
      } else {
        for (var i = 0; i < len; i++ ) {
          list[i]['checked'] = true;
        }
      }
      this.goodsObj[index]['checked'] = !this.goodsObj[index]['checked'];

      // 判断是否选择所有商品的全选
      this.isChooseAll();

      this.cal(index);
    },

    // 单个选择
    choose : function( index1, index) {
      var list = this.goodsObj[index1]['list'],
        len = list.length;
      if ( list[index]['checked'] ) {
        this.goodsObj[index1]['checked'] = false;
        this.allChecked = false;
        list[index]['checked'] = !list[index]['checked'];
      } else {
        list[index]['checked'] = !list[index]['checked'];

        // 判断是否选择当前店铺的全选
        var flag = true;
        for (var i = 0; i < len; i++ ) {
          if ( list[i]['checked'] == false ) {
            flag = false;
            break;
          }
        }
        flag == true ? this.goodsObj[index1]['checked'] = true : this.goodsObj[index1]['checked'] = false;
      }

      // 判断是否选择所有商品的全选
      this.isChooseAll();

      this.cal(index);
    },

    // 判断是否选择所有商品的全选
    isChooseAll : function() {
      var flag1 = true;
      for ( var i = 0, len = this.goodsObj.length; i < len; i++ ) {
        if ( this.goodsObj[i]['checked'] == false ) {
          flag1 = false;
          break;
        }
      }
      flag1 == true ? this.allChecked = true : this.allChecked = false;
    },

    // 商品数量控制
    numChange : function(index1, index, numChange) {
      var goods = this.goodsObj[index1]['list'][index],
        oThis = this;
      if ( numChange == 1 ) {
        goods.num++;
      } else if ( numChange == -1 ) {
        goods.num--;
      }

      if ( goods.num <= 1 ) {
        goods.num = 1;
      } 

      if ( goods.num >= goods.realStock ) {
        goods.num = goods.realStock;
      }

      this.cal(index);
    },

    // 用户填写容错处理
    numEntry : function(index1, index) {
      var goods = this.goodsObj[index1]['list'][index];
      if ( goods.num <=1 ) {
        goods.num = 1;
      }

      if ( goods.num > goods.realStock ) {
        goods.num = goods.realStock;
      }
      this.cal(index);
    },

    // 计算每个店铺的商品总额
    calEveryStore : function(index) {
      var everyStoreMoney = 0,
        list = this.goodsObj[index]['list'];
      list.forEach(function(item, index, arr) {
        if ( list[index]['checked'] ) { 
          everyStoreMoney += parseFloat(item.price) * parseFloat(item.num);
        }
      });
      return everyStoreMoney.toFixed(2);
    },

    // 计算每个店铺的运费总额
    calEveryFare : function(index) {
      var everyStoreFare = 0,
        list = this.goodsObj[index]['list'];
      list.forEach(function(item, index, arr) {
        if ( list[index]['checked'] ) { 
          everyStoreFare += parseFloat(item.fare) * parseFloat(item.num);
        }
      });
      return everyStoreFare.toFixed(2);
    },

    // 计算商品总金额
    calTotalMoney : function () {
      var oThis = this;
      this.totalMoney = 0;
      for ( var i = 0, len = this.goodsObj.length; i < len; i++ ) {
        var list = this.goodsObj[i]['list'];
        list.forEach(function(item, index, arr) {
          if ( list[index]['checked'] ) {
            oThis.totalMoney += parseFloat(item.price) * parseFloat(item.num);
          }
        });
      }
    },

    // 计算商品总运费
    calTotalFare : function () {
      var oThis = this;
      this.totalFare = 0;
      for ( var i = 0, len = this.goodsObj.length; i < len; i++ ) {
        var list = this.goodsObj[i]['list'];
        list.forEach(function(item, index, arr) {
          if ( list[index]['checked'] ) {
            oThis.totalFare += parseFloat(item.fare) * parseFloat(item.num);
          }
        });
      }
    },

    // 计算方法集合
    cal : function(index) {
      this.calEveryStore(index);
      this.calEveryFare(index);
      this.calTotalMoney();
      this.calTotalFare();
    },

    // 删除操作
    delGoods : function(index1, index) {
      console.log(index1);
      console.log(index);
      this.goodsObj[index1]['list'].splice(index, 1);
      this.cal(index);
    }
    
  }
})
</script>
</body>
</html>

效果如下:

vuejs手把手教你写一个完整的购物车实例代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 面向对象编程基础:封装
Aug 21 Javascript
Extjs入门之动态加载树代码
Apr 09 Javascript
javascript 学习笔记(八)javascript对象
Apr 12 Javascript
js实现点击左右按钮轮播图片效果实例
Jan 29 Javascript
基于Jquery插件Uploadify实现实时显示进度条上传图片
Mar 26 Javascript
深入理解javascript作用域第二篇之词法作用域和动态作用域
Jul 24 Javascript
深入理解Commonjs规范及Node模块实现
May 17 Javascript
Node.js  事件循环详解及实例
Aug 06 Javascript
JavaScript实现三级联动菜单效果
Aug 16 Javascript
在vue-cli的组件模板里使用font-awesome的两种方法
Sep 28 Javascript
浅谈Layui的eleTree树式选择器使用方法
Sep 25 Javascript
解决layui页面按钮点击无反应,也不报错的问题
Sep 29 Javascript
Vue axios 中提交表单数据(含上传文件)
Jul 06 #Javascript
解决webpack打包速度慢的解决办法汇总
Jul 06 #Javascript
详解微信小程序Radio选中样式切换
Jul 06 #Javascript
Node.js 回调函数实例详解
Jul 06 #Javascript
详解vue渲染从后台获取的json数据
Jul 06 #Javascript
微信小程序 Buffer缓冲区的详解
Jul 06 #Javascript
VUE axios发送跨域请求需要注意的问题
Jul 06 #Javascript
You might like
php中配置文件操作 如config.php文件的读取修改等操作
2012/07/07 PHP
深入Nginx + PHP 缓存详解
2013/07/11 PHP
php绘图之加载外部图片的方法
2015/01/24 PHP
PHP+iframe模拟Ajax上传文件功能示例
2019/07/02 PHP
php模拟post提交请求调用接口示例解析
2020/08/07 PHP
菜鸟学习JavaScript小实验之函数引用
2010/11/17 Javascript
基于jquery的blockui插件显示弹出层
2011/04/14 Javascript
javascript 快速排序函数代码
2012/05/30 Javascript
ff下JQuery无法监听input的keyup事件的解决方法
2013/12/12 Javascript
Mac OS X 系统下安装和部署Egret引擎开发环境
2014/09/03 Javascript
jQuery对于显示和隐藏等常用状态的判断方法
2014/12/13 Javascript
JavaScript设计模式经典之工厂模式
2016/02/24 Javascript
一个可复用的vue分页组件
2017/05/15 Javascript
自定义vue全局组件use使用、vuex的使用详解
2017/06/14 Javascript
JavaScript实现移动端页面按手机屏幕分辨率自动缩放的最强代码
2017/08/18 Javascript
JavaScript使用indexOf()实现数组去重的方法分析
2018/09/04 Javascript
python3音乐播放器简单实现代码
2020/04/20 Python
python字典DICT类型合并详解
2017/08/17 Python
Python除法之传统除法、Floor除法及真除法实例详解
2019/05/23 Python
你还在@微信官方?聊聊Python生成你想要的微信头像
2019/09/25 Python
Python3直接爬取图片URL并保存示例
2019/12/18 Python
浅谈python3 构造函数和析构函数
2020/03/12 Python
keras K.function获取某层的输出操作
2020/06/29 Python
python中查看.db文件中表格的名字及表格中的字段操作
2020/07/07 Python
python利用pytesseract 实现本地识别图片文字
2020/12/14 Python
多视角3D逼真HTML5水波动画
2016/03/03 HTML / CSS
美丽的珠宝配饰:SmallThings
2019/09/04 全球购物
学生的自我鉴定范文
2013/10/24 职场文书
应届大学毕业生找工作的求职信范文
2013/11/29 职场文书
医院门卫岗位职责
2013/12/30 职场文书
政法大学毕业生自荐信范文
2014/01/01 职场文书
厨房领班竞聘演讲稿
2014/04/23 职场文书
工作会议方案
2014/05/21 职场文书
《学会看病》教学反思
2016/02/17 职场文书
2016年万圣节活动个人总结
2016/04/05 职场文书
python基础之爬虫入门
2021/05/10 Python