Vue+Bootstrap实现购物车程序(2)

先简单看下效果图:(在原先基础上添加了删除和筛选操作)

代码:

 

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>购物车</title>
    <!--rel 属性指示被链接的文档是一个样式表,说白了就是指明你链进来的对象是个什么-->
    <link href="bootstrap.min.css" type="text/css" rel="stylesheet">
    <style type="text/css">
      button{
        outline: none;
      }
    </style>
</head>
<body>
  <!--
    container布局容器
    Bootstrap 需要为页面内容和栅格系统包裹一个 .container 容器。提供了两个作此用处的类。注意,由于 padding 等属性的原因,这两种 容器类不能互相嵌套。
    1、container 类用于固定宽度并支持响应式布局的容器。2、.container-fluid 类用于 100% 宽度,占据全部视口(viewport)的容器。
    -->
    <div id="app" class="container">
        <h1>购物车</h1>
        <hr>
        <btn-grp></btn-grp>
        <br>
        <br>
        <table class="table table-bordered table-striped table-hover">
            <tr>
              <td><input type="checkbox" v-on:click="selectAll" name="selectAllBtn"/></td>
              <th>ID</th>
              <th>商品名称</th>
              <th>商品价格</th>
              <th>商品数量</th>
              <th>商品总价</th>
            </tr>
            <tr v-for="(product,index) in products">
              <td>
                <input type="checkbox" v-on:click="checkItem(product)" v-model="product.state" name="checkbox" />
              </td>
              <td>{{index+1}}</td>
              <td>{{product.name}}</td>
              <td>{{product.price}}</td>
              <td>
                 <!--可以将两个按钮的方法合成一个,通过传参-->
                <!--<button @click="changeCount(prod, -1)">-</button>-->
                <button @click="cutCount(product)" class="btn btn-default btn-sm">-</button>
                <input type="number" v-model="product.count"/>
                <!--<button @click="changeCount(prod, 1)">-</button>-->
                <button @click="addCount(product)" class="btn btn-default btn-sm">+</button>
              </td>
              <td>{{product.price * product.count}}</td>
            </tr>
            <tr>
              <!--text-right排版文本右对齐-->
              <td colspan="5" class="text-right">总价:</td>
              <!--text-primary辅助类文本-->
              <td class="text-primary">{{totalMoney}}</td>
              <!--方法调用:<td class="text-primary">{{getTotalMoney()}}</td>-->
            </tr>
        </table>
    </div>
    <script type="application/javascript" src="vue-2.6.9.min.js"></script>
    <script type="application/javascript">
        Vue.component('btn-grp',{
          props:['button'],
          //btn-group:基本的按钮组。在 .btn-group 中放置一系列带有 class .btn 的按钮。
          //  role="group"按钮组合
          template:`
                  <div style="overflow: hidden">
                    <div class="btn-group" role="group" style="float:left;">
                      <button type="button"
                          v-for="button in buttons"
                          v-bind:class="\'btn \'+button.class"
                          v-on:click="button.handler"
                      >{{button.title}}</button>
                    </div>
                    <div style="float:right;">
                      <input class="form-control"
                        v-model="searchProduct"
                        @keyup.enter="filterProduct"
                        type="text"
                        placeholder="请输入商品名称"/>
                    </div>
                  </div>
          `,
          data:function(){
            return{
              searchProduct:'',
              buttons:[
                {title:'添加',class:'btn-primary',handler:function(){alert('点击添加按钮')}},
                {title:'修改',class:'btn-default',handler:function(){alert('点击修改按钮')}},
                {title:'删除',class:'btn-default',handler:function(){
                  for(let i =0;i<app.products.length;i++){
                    if(app.products[i].state){
                        app.products.splice(i,1);
                        i--;
                    }
                  };
                  /* 全选按钮状态清空 */
                  document.querySelectorAll('input[name="selectAllBtn"]')[0].checked = false;
                }}
              ]
            }
          },
          methods:{
            /* 商品筛选 */
            filterProduct:function(){
                var searchArr = [];
                for(let i=0;i<app.products.length;i++){
                  searchArr.push(app.products[i].name)
                }
                var searchIndex = searchArr.indexOf(this.searchProduct);
                if(searchIndex !== -1){
                  app.products = app.products.filter(function(element, index, self){
                    /* element数组元素、index元素索引、self数组本身 */
                    return index == searchIndex;
                  })
                }
            }
          }
        })
        var app = new Vue({
          el:'#app',
          data:{
            products: [
              {
                name: '小米6S',
                price: 3999,
                count: 1,
                state:false
              },
              {
                name: '锤子2',
                price: 4999,
                count: 1,
                state:false
              },
              {
                name: '华为P20',
                price: 3599,
                count: 1,
                state:false
              },
              {
                name: 'OPPO R15',
                price: 2999,
                count: 1,
                state:false
              },
              {
                name: 'OPPO R11',
                price: 1999,
                count: 1,
                state:false
              },
            ],
            searchProduct:''
          },
          methods:{
            // 用户点击加减数量时调用
            cutCount:function(product){
                if(product.count>0){
                  product.count--
                }else{
                  alert('商品数量不能小于0')
                }
            },
            addCount:function(product){
                product.count++
            },
            /*
             用户点击加减数量时调用通过传参合并为一个函数
             changeCount: function(prod, num) {
               if(num < 0) {
                 if(prod.count > 0) {
                  prod.count += num;
                 }
               }
               else {
                prod.count += num;
               }
             },
            */
            /*获取总价除了计算属性也可以用方法
             getTotalMoney: function() {
              var totalMoney = 0.0;
               for(var i = 0; i < this.products.length; ++i) {
                totalMoney += parseFloat(this.products[i].price * this.products[i].count);
               }
               return totalMoney;
             }
            */
            checkItem:function(product){
              product.state = !product.state;
            },
            selectAll:function() {
              var checkObj = document.querySelectorAll('input[name="checkbox"]'); // 获取所有checkbox项
              if (event.target.checked) {
                // 点击全选事件
                for (var i = 0; i < checkObj.length; i++) {
                  checkObj[i].checked = true;//选中样式
                  app.products[i].state = true;//动态改变值,供删除用
                }
              } else {
                for (var i = 0; i < checkObj.length; i++) {
                  checkObj[i].checked = false;
                  app.products[i].state = false;
                }
              }
            }
          },
          computed:{
            totalMoney:function(){
              var price = 0;
              for(var i = 0; i < this.products.length; ++i) {
                price += parseFloat(this.products[i].price * this.products[i].count);
              }
              return price;
            }
          }
        })
    </script>
</body>
</html>

 

修该:props传值

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>购物车</title>
    <!--rel 属性指示被链接的文档是一个样式表,说白了就是指明你链进来的对象是个什么-->
    <link href="bootstrap.min.css" type="text/css" rel="stylesheet">
    <style type="text/css">
      button{
        outline: none;
      }
    </style>
</head>
<body>
  <!--
    container布局容器
    Bootstrap 需要为页面内容和栅格系统包裹一个 .container 容器。提供了两个作此用处的类。注意,由于 padding 等属性的原因,这两种 容器类不能互相嵌套。
    1、container 类用于固定宽度并支持响应式布局的容器。2、.container-fluid 类用于 100% 宽度,占据全部视口(viewport)的容器。
    -->
    <div id="app" class="container">
        <h1>购物车</h1>
        <hr>
        <btn-grp v-bind:buttons="buttons"></btn-grp>
        <br>
        <br>
        <table class="table table-bordered table-striped table-hover">
            <tr>
              <td><input type="checkbox" v-on:click="selectAll" name="selectAllBtn"/></td>
              <th>ID</th>
              <th>商品名称</th>
              <th>商品价格</th>
              <th>商品数量</th>
              <th>商品总价</th>
            </tr>
            <tr v-for="(product,index) in products">
              <td>
                <input type="checkbox" v-on:click="checkItem(product)" v-model="product.state" name="checkbox" />
              </td>
              <td>{{index+1}}</td>
              <td>{{product.name}}</td>
              <td>{{product.price}}</td>
              <td>
                 <!--可以将两个按钮的方法合成一个,通过传参-->
                <!--<button @click="changeCount(prod, -1)">-</button>-->
                <button @click="cutCount(product)" class="btn btn-default btn-sm">-</button>
                <input type="number" v-model="product.count"/>
                <!--<button @click="changeCount(prod, 1)">-</button>-->
                <button @click="addCount(product)" class="btn btn-default btn-sm">+</button>
              </td>
              <td>{{product.price * product.count}}</td>
            </tr>
            <tr>
              <!--text-right排版文本右对齐-->
              <td colspan="5" class="text-right">总价:</td>
              <!--text-primary辅助类文本-->
              <td class="text-primary">{{totalMoney}}</td>
              <!--方法调用:<td class="text-primary">{{getTotalMoney()}}</td>-->
            </tr>
        </table>
    </div>
    <script type="application/javascript" src="vue-2.6.9.min.js"></script>
    <script type="application/javascript">
        Vue.component('btn-grp',{
          props:['buttons'],
          //btn-group:基本的按钮组。在 .btn-group 中放置一系列带有 class .btn 的按钮。
          //  role="group"按钮组合
          template:`
                  <div style="overflow: hidden">
                    <div class="btn-group" role="group" style="float:left;">
                      <button type="button"
                          v-for="button in buttons"
                          v-bind:class="\'btn \'+button.class"
                          v-on:click="button.handler"
                      >{{button.title}}</button>
                    </div>
                    <div style="float:right;">
                      <input class="form-control"
                        v-model="searchProduct"
                        @keyup.enter="filterProduct"
                        type="text"
                        placeholder="请输入商品名称"/>
                    </div>
                  </div>
          `,
          data:function(){
            return{
              searchProduct:''
            }
          },
          methods:{
            /* 商品筛选 */
            filterProduct:function(){
                var searchArr = [];
                for(let i=0;i<app.products.length;i++){
                  searchArr.push(app.products[i].name)
                }
                var searchIndex = searchArr.indexOf(this.searchProduct);
                if(searchIndex !== -1){
                  app.products = app.products.filter(function(element, index, self){
                    /* element数组元素、index元素索引、self数组本身 */
                    return index == searchIndex;
                  })
                }else{
                  alert('暂无符合商品');
                }
            }
          }
        })
        var app = new Vue({
          el:'#app',
          data:{
            products: [
              {
                name: '小米6S',
                price: 3999,
                count: 1,
                state:false
              },
              {
                name: '锤子2',
                price: 4999,
                count: 1,
                state:false
              },
              {
                name: '华为P20',
                price: 3599,
                count: 1,
                state:false
              },
              {
                name: 'OPPO R15',
                price: 2999,
                count: 1,
                state:false
              },
              {
                name: 'OPPO R11',
                price: 1999,
                count: 1,
                state:false
              },
            ],
            searchProduct:'',
            buttons:[
              {title:'添加',class:'btn-primary',handler:function(){alert('点击添加按钮')}},
              {title:'修改',class:'btn-default',handler:function(){alert('点击修改按钮')}},
              {title:'删除',class:'btn-default',handler:function(){
                for(let i =0;i<app.products.length;i++){
                  if(app.products[i].state){
                    app.products.splice(i,1);
                    i--;
                  }
                };
                /* 全选按钮状态清空 */
                document.querySelectorAll('input[name="selectAllBtn"]')[0].checked = false;
              }}
            ]
          },
          methods:{
            // 用户点击加减数量时调用
            cutCount:function(product){
                if(product.count>0){
                  product.count--
                }else{
                  alert('商品数量不能小于0')
                }
            },
            addCount:function(product){
                product.count++
            },
            /*
             用户点击加减数量时调用通过传参合并为一个函数
             changeCount: function(prod, num) {
               if(num < 0) {
                 if(prod.count > 0) {
                  prod.count += num;
                 }
               }
               else {
                prod.count += num;
               }
             },
            */
            /*获取总价除了计算属性也可以用方法
             getTotalMoney: function() {
              var totalMoney = 0.0;
               for(var i = 0; i < this.products.length; ++i) {
                totalMoney += parseFloat(this.products[i].price * this.products[i].count);
               }
               return totalMoney;
             }
            */
            checkItem:function(product){
              product.state = !product.state;
            },
            selectAll:function() {
              var checkObj = document.querySelectorAll('input[name="checkbox"]'); // 获取所有checkbox项
              if (event.target.checked) {
                // 点击全选事件
                for (var i = 0; i < checkObj.length; i++) {
                  checkObj[i].checked = true;//选中样式
                  app.products[i].state = true;//动态改变值,供删除用
                }
              } else {
                for (var i = 0; i < checkObj.length; i++) {
                  checkObj[i].checked = false;
                  app.products[i].state = false;
                }
              }
            }
          },
          computed:{
            totalMoney:function(){
              var price = 0;
              for(var i = 0; i < this.products.length; ++i) {
                price += parseFloat(this.products[i].price * this.products[i].count);
              }
              return price;
            }
          }
        })
    </script>
</body>
</html>

 

 

 

 

.

posted @ 2019-03-31 16:20  剑仙6  阅读(554)  评论(0编辑  收藏  举报
欢迎访问个人网站www.qingchun.在线