«

购物车

yang 发布于 阅读:437 Vue2阶段


1. 购物车

1.1 布局样式

固定定位 position:fixed;

1.2 购物车交互

第一步:在获取到商品数据后,给每一个商品添加一个数量属性,用于记录商品的购物数量

//给每一个商品添加一个购物数量的属性
res.data.data.forEach(v=>{
  v.foods.forEach(v2=>{
    v2.cartNum=0;
  });
});

第二步:将商品列表添加到vuex,用于计算购物车商品列表

export default new Vuex.Store({
  state: {
    goodsList:[], //商品列表
    cartList:[], //购物车列表
  },
  mutations: {
    //存储商品列表
    addGoods(state, payload){
      state.goodsList = payload;
    },
  },
})

第三步:点击加减时计算购物车商品

mutations: {
    //计算购物车商品数量
    addCart(state, payload){
      let arr=[];
      state.goodsList.forEach(v=>{
        v.foods.forEach(v2=>{
          //遍历所有商品,商品购物车数量大于0,添加到购物车
          if(v2.cartNum>0){
            arr.push(v2); //为了防止商品重复叠加,所以需要用一个临时变量进行计算存储
          }
        })
      })

      state.cartList = arr; //替换掉以前的
    }
},

第四步:根据购物车商品数量显示样式

<!--购物车图标-->
<van-badge :content="cartList.length" v-if="cartList.length>0">
  <van-icon name="shopping-cart" class="active"/>
</van-badge>
<van-icon name="shopping-cart" v-else/>

<!--去结算-->
<div :class="{active: cartList.length>0}">
  <span v-if="cartList.length>0">去结算</span>
  <span v-else>¥20元起送</span>
</div>

第五步:计算商品总价

//计算购物车商品总价
total(){
  let sum=0;
  this.cartList.forEach(v=>{
    sum+=v.cartNum * v.price;
  })
  return sum;
},

第六步:渲染购物车商品列表

//清空购物车
clearCart(state, payload){
  state.cartList = [];

  //清空商品列表中所有购物数量
  state.goodsList.forEach(v=>{
    v.foods.forEach(v2=>{
      v2.cartNum=0;
    })
  })
}

1.3 数据跨页面共享的问题

问题:vuex的数据可以实现跨页面共享,页面切回来时会重新发请求获取数据,并写入vuex,数据被覆盖

解决:在发请求前,判断一下vuex里面有没有数据,如果有就不发请求,如果没有就要发请求

//判断当前vuex里面有没有数据,如果没有就发请求
if(this.list.length===0){
  //获取商品信息
  let res = await goodsList();

  //给每一个商品添加一个购物数量的属性
  res.data.data.forEach(v=>{
    v.foods.forEach(v2=>{
      v2.cartNum=0;
    });
  });

  //将读取到的数据存储到vuex
  this.$store.commit('addGoods', res.data.data);
}

代码具体实现:

<template>
    <!-- 购物车的独立组件 -->
    <div>
        <div class="cart">
            <div><van-icon name="smile-o" />联系商家</div>
            <div @click="show=!show">
                <van-badge :content="cartList.length" v-if="cartList.length>0">
                    <van-icon name="shopping-cart" class="active"/>
                </van-badge>
                <van-icon name="shopping-cart" v-else/>
            </div>
            <div>
                <strong>¥{{total | fixed}}</strong>
                另需配送费¥4元 | 支持自取
            </div>
            <div :class="{active: cartList.length>0}">
                <span v-if="cartList.length>0">去结算</span>
                <span v-else>¥20元起送</span>
            </div>
        </div>

        <van-popup v-model="show" round position="bottom">
            <h3>新用户下单立减5元</h3>
            <div class="opt"><strong>购物车</strong>  <span @click="clear"><van-icon name="delete-o" /> 清空购物车</span></div>
            <ul>
                <li v-for="(v,i) in cartList" :key="i">
                    <div class="title">{{v.name}}</div>
                    <strong>¥{{v.cartNum*v.price | fixed}}</strong>
                    <van-stepper v-model="v.cartNum" theme="round" button-size="20" disable-input />
                </li>
            </ul>
        </van-popup>
    </div>
</template>
<script>
import {mapState} from 'vuex';

export default {
    data(){
        return {
            show:false,
        }
    },

    methods:{
        //清空购物车
        clear(){
            this.$store.commit('clearCart');
            this.show=false;
        }
    },

    computed:{
        ...mapState(['cartList']), //辅助函数读取vuex购物车数据

        //计算购物车商品总价
        total(){
            let sum=0;
            this.cartList.forEach(v=>{
                sum+=v.cartNum * v.price;
            })
            return sum;
        },
    },

    filters:{
        //保留两位小数的过滤器
        fixed(n){
            return n.toFixed(2);
        }
    }
}
</script>
<style lang="less" scoped>
.cart{
    position:fixed;
    bottom:10px;
    z-index:99999;
    left:3%;
    width:94%;
    height:60px;

    display:flex;
    background:#222;
    color:#999;
    font-size:12px;
    border-radius:30px;
    overflow:hidden;

    &>div:nth-child(1){
        width:66px;
        border-right:3px solid #fff;
        text-align:center;
        .van-icon{
            font-size:24px;
            display:block;
            padding-top:6px;
        }
    }

    &>div:nth-child(2){
        width:60px;

        .van-icon{
            font-size:35px;
            background:#333;
            padding:8px;
            border-radius:100%;
            margin:5px;
        }

        .active{
            background:#ffc300;
            color:#000;
        }

        :deep(.van-badge--fixed){
            top:12px;
            right:10px;
        }
    }

    &>div:nth-child(3){
        font-size:12px;
        padding-top:12px;
        flex-grow:1;
        strong{
            display:block;
            color:#fff;
            font-size:20px;
        }
    }

    &>div:nth-child(4){
        line-height:60px;
        width:66px;
    }

    &>div:nth-child(4).active{
        background:#ffc300;
        color:#000;
        text-align:center;
        font-size:16px;
    }
}

.van-popup{
    padding-bottom:80px;

    h3{
        text-align:center;
        font-weight:normal;
        color:#e04c1f;
        background:#fee7c8;
        line-height:32px;
        font-size:14px;
    }

    .opt{
        display:flex;
        justify-content:space-between;
        line-height:30px;
        padding:0 10px;
    }

    ul{
        padding:10px;

        li{
            display:flex;
            padding:10px 0;
            .title{
                width:1px;
                flex-grow:1;
                overflow:hidden;
                white-space:nowrap;
                text-overflow:ellipsis;
            }

            strong{
                width:80px;
                color:#f00;
            }
        }
    }
}
</style>

vuex数据

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    goodsList:[], //商品列表
    cartList:[], //购物车列表
  },
  getters: {
  },
  mutations: {
    //存储商品列表
    addGoods(state, payload){
      state.goodsList = payload;
    },

    //计算购物车商品数量
    addCart(state, payload){
      let arr=[];
      state.goodsList.forEach(v=>{
        v.foods.forEach(v2=>{
          //遍历所有商品,商品购物车数量大于0,添加到购物车
          if(v2.cartNum>0){
            arr.push(v2); //为了防止商品重复叠加,所以需要用一个临时变量进行计算存储
          }
        })
      })

      state.cartList = arr; //替换掉以前的
    },

    //清空购物车
    clearCart(state, payload){
      state.cartList = [];

      //清空商品列表中所有购物数量
      state.goodsList.forEach(v=>{
        v.foods.forEach(v2=>{
          v2.cartNum=0;
        })
      })
    }
  },
  actions: {
  },
  modules: {
  }
})

版权所有:微4e
文章标题:购物车
除非注明,文章均为 微4e 原创,请勿用于任何商业用途,禁止转载

推荐阅读:


扫描二维码,在手机上阅读
请先 登录 再评论