使用vue实现购物车案例

2022-10-07 09:19:45

1. 实现步骤

在这里插入图片描述
【备注】这里的接口地址目前(2022年6月)还是可以用的哦~

2. 实现

2.1 代码结构

在这里插入图片描述
使用的样式是Boostrap,需要npm i bootstrap,然后在main.js中引入bootstrap。
在这里插入图片描述

2.2 Header头部的代码
<template><divclass="header-container">{{ title}}</div></template><script>exportdefault{props:{title:{default:'',type: String}}};</script><style lang="less" scoped>.header-container{
  font-size: 12px;height: 45px;width:100%;
  background-color: #1d7bff;display: flex;
  justify-content: center;
  align-items: center;color: #fff;position: fixed;top:0;
  z-index:999;left:0;}</style>
2.3 Goods商品组件代码

在这里插入图片描述
代码:

<template><divclass="goods-container"><!-- 左侧图片--><divclass="thumb"><divclass="custom-control custom-checkbox"><!-- 复选框--><input
          type="checkbox"class="custom-control-input":id="'cb' + id":checked="state"
          @change="stateChange"/><labelclass="custom-control-label":for="'cb' + id"><!-- 商品的缩略图--><img:src="pic" alt=""/></label></div></div><!-- 右侧信息区域--><divclass="goods-info"><!-- 商品标题--><h6class="goods-title">{{ title}}</h6><divclass="goods-info-bottom"><!-- 商品价格--><spanclass="goods-price">{{ price}}</span><!-- 商品的数量--><Counter:num="count":id="id"></Counter></div></div></div></template><script>import Counterfrom'../Counter/Counter.vue';exportdefault{props:{id:{required:true,type: Number,},title:{default:"",type: String,},pic:{default:"",type: String,},price:{default:0,type: Number,},state:{default:true,type: Boolean,},count:{default:1,type: Number,}},methods:{// 复选框发生改变,调用这个事件stateChange(e){// console.log(e);const newState= e.target.checked;// console.log(this.id);// 触发自定义事件(子传父)this.$emit('state-change',{id:this.id,value: newState})}},components:{
    Counter,}};</script><style lang="less" scoped>.goods-container{+.goods-container{
    border-top: 1px solid #efefef;}padding: 10px;display: flex;.thumb{display: flex;
    align-items: center;
    img{width: 100px;height: 100px;margin:0 10px;}}.goods-info{display: flex;
    flex-direction: column;
    justify-content: space-between;flex:1;.goods-title{
      font-weight: bold;
      font-size: 12px;}.goods-info-bottom{display: flex;
      justify-content: space-between;.goods-price{
        font-weight: bold;color: red;
        font-size: 13px;}}}}</style>
2.4 Footer组件代码
<template><divclass="footer-container"><!-- 左侧的全选--><divclass="custom-control custom-checkbox"><input
        type="checkbox"class="custom-control-input"
        id="cbFull":checked="isFull"
        @change="fullChange"/><labelclass="custom-control-label"for="cbFull">全选</label></div><!-- 中间的合计--><div><span>合计:</span><spanclass="total-price">{{ amount.toFixed(2)}}</span></div><!-- 结算按钮--><button type="button"class="btn btn-primary btn-settle">
      结算({{ all}}</button></div></template><script>exportdefault{props:{isFull:{default:true,type: Boolean,},amount:{default:0,type: Number,},all:{default:0,type: Number,}},methods:{// 监听全选的状态变化fullChange(e){// console.log(e.target.checked);this.$emit("full-change", e.target.checked);},},};</script><style lang="less" scoped>.footer-container{
  font-size: 12px;height: 50px;width:100%;
  border-top: 1px solid #efefef;position: fixed;bottom:0;
  background-color: #fff;display: flex;
  justify-content: space-between;
  align-items: center;padding:0 10px;}.custom-checkbox{display: flex;
  align-items: center;}

#cbFull{
  margin-right: 5px;}.btn-settle{height:80%;
  min-width: 110px;
  border-radius: 25px;
  font-size: 12px;color: #fff;
  background-color: #1d7bff;border:0;}.total-price{
  font-weight: bold;
  font-size: 14px;color: red;}</style>
2.5 Counter组件代码
<template><divclass="number-container d-flex justify-content-center align-items-center"><!--1 的按钮--><button type="button"class="btn btn-light btn-sm" @click="sub">-</button><!-- 购买的数量--><spanclass="number-box">{{ num}}</span><!--1 的按钮--><button type="button"class="btn btn-light btn-sm" @click="add">+</button></div></template><script>import busfrom'@/components/eventBus.js';exportdefault{props:{// 接收商品的id,将来使用eventBus方案,把数量传递到app.vue的时候,需要通知App组件,更新哪个商品的数量id:{type: Number,required:true,},num:{default:1,type: Number,},},methods:{// 点击按钮,数值加1add(){// 要发送给App的数据,id是商品的id,value是商品的数量const obj={id:this.id,value:this.num+1,}// 通过eventBus把obj对象发送给App.vue组件// console.log(obj);
      bus.$emit('share', obj);},// 点击按钮,数值减1sub(){if(this.num-1===0)return;const obj={id:this.id,value:this.num-1,}
      bus.$emit('share', obj);}}};</script><style lang="less" scoped>.number-box{
  min-width: 30px;
  text-align: center;margin:0 5px;
  font-size: 12px;}.btn-sm{width: 30px;}</style>
2.6 App.vue根组件代码
<template><div id="app-container"><hr><!-- 头部区域--><Header title="购物车案例"></Header><!--商品列表(循环渲染每一个商品的信息)--><Goods
      v-for="item in list":key="item.id":id="item.id":title="item.goods_name":pic="item.goods_img":price="item.goods_price":state="item.goods_state":count="item.goods_count"
      @state-change="getNewState"></Goods><!-- footer区域--><Footer:isFull="fullState":amount="amt":all="total"
      @full-change="getFullState"></Footer><br></div></template><script>import axiosfrom"axios";import Headerfrom"@/components/Header/Header";import Goodsfrom"./components/Goods/Goods.vue";import Footerfrom"@/components/Footer/Footer";import busfrom'@/components/eventBus.js';exportdefault{data(){return{// 用来存储购物车列表数据,默认为空数组list:[],};},methods:{// 封装请求列表数据的方法asyncinitCardList(){const{data: res}=await axios.get("https://www.escook.cn/api/cart");// console.log(res);if(res.status===200){this.list= res.list;}// console.log(this.list);},// 接收子组件发来的数据getNewState(e){// console.log(e);this.list.some((item)=>{if(item.id=== e.id){
          item.goods_state= e.value;returntrue;}});},// 接收Footer子组件发来的全选状态getFullState(val){// console.log(val);this.list.forEach((item)=>{
        item.goods_state= val;});},},components:{
    Header,
    Goods,
    Footer,},created(){this.initCardList();
    bus.$on('share',(val)=>{// console.log(val);this.list.some(item=>{if(item.id=== val.id){
          item.goods_count= val.value;// 终止循环returntrue;}})})},computed:{// 动态计算出全选的状态是 true 还是 falsefullState(){returnthis.list.every((item)=> item.goods_state);},// 已勾选状态的商品总价amt(){// 1. 先filter过滤// 2. 再reduce累加returnthis.list.filter(item=>item.goods_state).reduce((total, item)=>{return total+= item.goods_price* item.goods_count;},0)},// 已勾选的数量总数total(){returnthis.list.filter(item=>item.goods_state).reduce((t,item)=>{return t+= item.goods_count;},0)}},};</script><style lang="less">.app-container{
  padding-top: 45px;
  padding-bottom: 50px;}</style>
2.7 eventBus.js 代码

在这里插入图片描述

import Vuefrom'vue';exportdefaultnewVue()
2.8 效果

在这里插入图片描述

3. 总结

3.1 组件之间的嵌套关系
  1. App为根组件
  2. App有三个子组件:Header、Goods、Footer;
  3. Goods有一个子组件:Counter;
3.2 这个案例涉及到的知识点
  1. 使用axios的get方法获取商品信息列表;
  2. vue的组件化;
  3. v-bind、v-for、@事件绑定;
  4. 父组件向子组件传值
  • 作者:想做一只快乐的修狗
  • 原文链接:https://blog.csdn.net/weixin_44109827/article/details/125245778
    更新时间:2022-10-07 09:19:45