购物车案例

本文档展示了如何使用Vue.js实现一个购物车功能,包括组件化设计、商品列表展示、数量增减及总价计算。通过创建标题、列表和结算组件,实现了商品的动态交互,并提供了代码实例,涉及组件通信、数据处理和样式布局。
摘要由CSDN通过智能技术生成

购物车案例

效果图如下:
购物车

1. 按照组件化方式实现业务需求

1.1根据业务功能进行组件化划分

①标题组件(展示文本)
②列表组件(列表展示·商品数量变更·商品删除)
③结算的组件(计算商品总额)

2. 功能实现步骤

①实现整体布局和样式效果
②划分独立的功能组件
③组合所有的子组件形成整体结构
④逐个实现各个组件功能
*标题组件
*列表组件
*结算组件

3.代码如下

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .container .cart {
      width: 300px;
      margin: auto;
    }

    .container .title {
      background-color: lightblue;
      height: 40px;
      line-height: 40px;
      text-align: center;
      /*color: #fff;*/
    }

    .container .total {
      background-color: #FFCE46;
      height: 50px;
      line-height: 50px;
      text-align: right;
    }

    .container .total button {
      margin: 0 10px;
      background-color: #DC4C40;
      height: 35px;
      width: 80px;
      border: 0;
    }

    .container .total span {
      color: red;
      font-weight: bold;
    }

    .container .item {
      height: 55px;
      line-height: 55px;
      position: relative;
      border-top: 1px solid #ADD8E6;
    }

    .container .item img {
      width: 45px;
      height: 45px;
      margin: 5px;
    }

    .container .item .name {
      position: absolute;
      width: 90px;
      top: 0;
      left: 55px;
      font-size: 16px;
    }

    .container .item .change {
      width: 100px;
      position: absolute;
      top: 0;
      right: 50px;
    }

    .container .item .change a {
      font-size: 20px;
      width: 30px;
      text-decoration: none;
      background-color: lightgray;
      vertical-align: middle;
    }

    .container .item .change .num {
      width: 40px;
      height: 25px;
    }

    .container .item .del {
      position: absolute;
      top: 0;
      right: 0px;
      width: 40px;
      text-align: center;
      font-size: 40px;
      cursor: pointer;
      color: red;
    }

    .container .item .del:hover {
      background-color: orange;
    }
  </style>
</head>

<body>
  <div id="app">
    <div class="container">
      <my-cart></my-cart>
    </div>
  </div>
  <script src="js/vue.js"></script>
  <script>
    // 局部组件
    var CartTitle = {
      props: ['uname'],
      // 传递名字  那么就用到了父传子
      template: `<div class="title">{{uname}}商品</div>`

    };
    var CartList = {
      props: ['list'],
      // 删除事件最好在父组件中删除 那么就应该用到了子传父
      // 给子一个点击事件 
      // 子组件通过自定义事件给父组件发送信息
      // /父组件监听子组件发过来的信息
      template: `

      <div>
        <div class="item" v-for='item in list'>
          <img :src="item.img" />
          <div class="name">{{item.name}}</div>
          <div class="change">
            <a href="" @click.prevent='sub(item.id)'>-</a>
            <input type="text" class="num" :value='item.num' @blur='changeNum(item.id, $event)''/>
            <a href=""  @click.prevent='add(item.id)' >+</a>
          </div>
          <div class="del" @click='handle(item.id)'>×</div>
        </div>
        </div>
      `,
      methods: {
        sub: function (id) {
          // console.log(id);
          // 区分加减法所以加一个type
          this.$emit('change-num', {
            id: id,
            //
            type: 'sub'
          });
        },
        add: function (id) {
          // console.log(id);
          // 区分加减法所以加一个type
          this.$emit('change-num', {
            id: id,
            //
            type: 'add'
          });
        },
        changeNum: function (id, event) {
          // 获取到id和值
          // console.log(id, event.target.value);
          // 触发自定义事件   因为需要两项  所以用对象的形式
          this.$emit('change-num', {
            id: id,
            num: event.target.value,
            // 怕影响changeNum所以也给他加上去一个
            type: 'change'

          });

        },

        // 获取点击的id  所以这里要接收
        handle: function (id) {
          this.$emit('del-cart', id);
        }
      }

    };
    var CartTotal = {
      props: ['list'],
      data: function () {
        return {

        }
      },

      template: ` 
      <div class="total">
        <span>总价:{{total}}</span>
        <button>结算</button>
      </div>`,
      computed: {
        total: function () {
          var t = 0;
          // 遍历list   item 是元素
          this.list.forEach(item => {
            t += item.price * item.num;

          });
          return t;
        }
      }
    };
    // 定义全局组件
    Vue.component('my-cart', {
      data: function () {
        return {
          uname: '张三',
          list: [
            {
              id: 1,
              name: 'TCL彩电',
              price: 1000,
              num: 1,
              img: 'img/a.jpg'
            }, {
              id: 2,
              name: '机顶盒',
              price: 1000,
              num: 1,
              img: 'img/b.jpg'
            }, {
              id: 3,
              name: '海尔冰箱',
              price: 1000,
              num: 1,
              img: 'img/c.jpg'
            }, {
              id: 4,
              name: '小米手机',
              price: 1000,
              num: 1,
              img: 'img/d.jpg'
            }, {
              id: 5,
              name: 'PPTV电视',
              price: 1000,
              num: 2,
              img: 'img/e.jpg'
            }

          ]
        }
      },
      // 定义局部组件
      components: {
        'cart-title': CartTitle,
        'cart-list': CartList,
        'cart-total': CartTotal
      },
      template: `
      <div class='cart'>
      <cart-title :uname='uname'></cart-title>
        <cart-list :list='list'  @change-num='changeNum($event)' @del-cart='delCart'></cart-list>
          <cart-total :list='list' ></cart-total>
       </div>
      `,

      methods: {
        // 到底是加号还是减号  得用一个标志
        changeNum: function (val) {
          // 有三种情况 根据type区分
          if (val.type == 'change') {
            // console.log(val);
            // 根据子组件传递过来的数据,更新list对应的数据
            this.list.some(item => {
              // 遍历的每条数据item  他是list里的  用双等号不能用=
              if (item.id == val.id) {
                // 如果不终止 就会让所有的num等于当前失去焦点的num
                item.num = val.num;
                // 终止遍历   终止此时的if条件
                return true;
                // console.log(val);
              }
              // 写到这就只能执行一次  这里终止 会让所有的都终止
              // return true
            })
          } else if (val.type == 'sub') {
            this.list.some(item => {
              // 遍历的每条数据item  他是list里的  用双等号不能用=
              if (item.id == val.id) {
                // 如果不终止 就会让所有的num等于当前失去焦点的num
                while (item.num > 0)
                  item.num -= 1;

                // 终止遍历   终止此时的if条件
                return true;
                // console.log(val);
              }
              // 写到这就只能执行一次  这里终止 会让所有的都终止
              // return true
            })
          } else if (val.type == 'add') {
            this.list.some(item => {
              // 遍历的每条数据item  他是list里的  用双等号不能用=
              if (item.id == val.id) {
                // 如果不终止 就会让所有的num等于当前失去焦点的num
                // 解决字符串的拼接问题
                item.num = parseInt(item.num)
                item.num += 1;
                // 终止遍历   终止此时的if条件
                return true;
                // console.log(val);
              }
              // 写到这就只能执行一次  这里终止 会让所有的都终止
              // return true
            })
          }

        },
        delCart: function (id) {
          // 进行比对 
          var index = this.list.findIndex(item => {
            return item.id = id;
          });
          this.list.splice(index, 1)
        }

      }
    });
    var vm = new Vue({
      el: '#app',
      data: {
      },
      methods: {
      }
    })
  </script>
</body>

</html>

4.注意

①字符串转化为数字利用parseInt
item.num = parseInt(item.num)
②减去数量的时候数字不能小于0 利用了while循环
while (item.num > 0)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值