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

效果展示:(说明:使用webpack重构购物车程序,使用vue-cli生成项目脚手架)

 

 

文件结构:

 

 

代码:

(1)将原来编写的btn-grp组件单独编写到BtnGrp.vue文件中

  • 可以看到现在代码清晰了很多,template标签部分编写模板,script标签部分编写组件的交互代码,编写方式和原先写在HTML的代码一致

  • 现在整个前端应用都是基于组件化的,代码变得更加清晰了

<!--vue组件-->
<template>
    <div style="float:right;">
      <input class="form-control"
             v-model="searchProduct"
             @keyup.enter="filterProduct"
             type="text"
             placeholder="请输入商品名称"/>
    </div>
</template>

<script type="application/javascript">
//    import App from '../App';
    export default{
      name:"BtnGroup",
      props:['products'],
      data:function(){
        return {
          searchProduct:''
        }
      },
      methods:{
        /* 商品筛选 */
        filterProduct:function(){
//          console.log(this.$parent.products)
          var searchArr = [];
          for(let i=0;i<this.$parent.products.length;i++){
            searchArr.push(this.$parent.products[i].name)
          }
          var searchIndex = searchArr.indexOf(this.searchProduct);
          if(searchIndex !== -1){
            this.$parent.products = this.$parent.products.filter(function(element, index, self){
              /* element数组元素、index元素索引、self数组本身 */
              return index == searchIndex;
            })
          }else{
            alert('暂无符合商品');
          }
        }
      }

    }
//    module.exports = BtnGroup;
//    export default BtnGroup;
//  export default {
//    props: ['buttons']
//  }
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<!--翻译:添加“scoped”属性以仅将CSS限制为此组件-->
<style type="text/css" scoped>

</style>

(2)将原来写在HTML中的代码重构到App.vue中

  • 此处因为需要用到BtnGrp组件,所以需要先import 组件,然后在components中引用该组件

<!--主页组件-->

<template>
  <div id="app" class="container">
    <h1>购物车</h1>
    <hr>
    <!--<BtnGroup v-bind:buttons="buttons"></BtnGroup>-->
    <div style="overflow: hidden">
      <div style="float: left">
        <button type="button" v-on:click="addHandler" class="btn btn-primary">添加</button>
        <button type="button" v-on:click="changeHandler" class="btn btn-default">修改</button>
        <button type="button" v-on:click="delateHandler" class="btn btn-default">删除</button>
      </div>
      <BtnGroup :products="products"></BtnGroup>
    </div>
    <br>
    <br>
    <table class="table table-bordered table-striped table-hover">
      <tr>
        <td><input type="checkbox" v-on:click="selectAll" name="selectAllBtn" v-model="selectAllState"/></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>
      </tr>
    </table>
  </div>
</template>

<script>
  /* eslint-disable no-new */
  import 'bootstrap/dist/css/bootstrap.min.css'
  import BtnGroup from './components/BtnGroup'
  export default{
    name: 'App',
    components: {BtnGroup},
    data:function(){
      return{
        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
          },
        ],
        selectAllState:false
        /*
          注意:这里修正下,页面里的死数据,操作类的直接写好即可,不用遍历数据获取。
          只有页面中的展示信息即动态设置
         */
        /*
        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.data().products.length;i++){
//              console.log(app.data().products[i].state)
              if(app.data().products[i].state){
                app.data().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++
      },
      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;//选中样式
            this.products[i].state = true;//动态改变值,供删除用
          }
        } else {
          for (var i = 0; i < checkObj.length; i++) {
            checkObj[i].checked = false;
            this.products[i].state = false;
          }
        }
      },
      /*添加 */
      addHandler:function(){
        alert("点击添加按钮")
      },
      /* 修改 */
      changeHandler:function(){
        alert("点击修改按钮")
      },
      /* 删除 */
      delateHandler:function(){
        for(let i=0;i<this.products.length;i++){
          if(this.products[i].state){
            this.products.splice(i,1);
            i--;
          }
        }
         /* 注意:vue里尽量避免DOM操作。所有的操作都是数据驱动 */
        this.selectAllState = 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;
      }
    }

  }
//  module.exports = App;
//  export default app;

</script>

<style>
  #app {
    font-family: 'Avenir', Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
  }
</style>

 

posted @ 2019-04-01 10:24  剑仙6  阅读(805)  评论(0编辑  收藏  举报
欢迎访问个人网站www.qingchun.在线