Vue3+Vite+Vant3 购物车(单选全选,数量增减,金额计算,左滑删除,空状态,结算跳转)

发布于:2022-11-27 ⋅ 阅读:(1292) ⋅ 点赞:(0)

场景简述:

1、没有购物车接口,购物车数据存储在本地缓存中,名为 carts ;

2、carts中的商品信息没有图片,所以没渲染图片;

3、使用了Vant3组件;

4、没有使用eslint格式化;

5、<script setup></script>

使用到的Vant3组件:

app.use(Icon);

app.use(NavBar);

app.use(Button);

app.use(SubmitBar);

app.use(Checkbox);

app.use(CheckboxGroup);

app.use(Empty);

app.use(Stepper);

0、简洁版:

效果图:

单选+数量增减+金额计算

全选+删除单个商品

空状态 

 完整代码:

<template>
  <div class="cart">
    <!-- 头部 -->
    <div class="header" >
      <a href="javascript:history.go(-1)"><van-icon name="arrow-left" class="arrow-left"/></a>
      <van-nav-bar title="购物车" fixed/>
    </div>

    <!-- 购物车start -->
    <div class="cart_container">

      <!-- vant空状态 -->
      <van-empty v-show="isShow" description="购物车目前还没有商品" image="https://img.yzcdn.cn/vant/custom-empty-image.png">
         <router-link to="/goods">
          <van-button round type="danger" class="bottom-button">
            去购物
          </van-button>
         </router-link> 
        </van-empty>
      <!-- 空状态end -->

      <!-- 购物车start -->
      <div v-for="(item,index) in store" :key="index" class="list">
        <van-swipe-cell>

          <!-- 选框 -->
          <div class="checkbox">
            <van-checkbox
            :name="item" 
            v-model="item.checked"
            @change=onChecked
            checked-color="#f11a27"
            ></van-checkbox>
          </div>

          <!-- 商品信息 -->
          <div class="goods_info">
            <div class="title">{{item.title}}</div>
            <div class="bottom">
              <div class="price">
                <span>¥</span>
                {{item.sell_price}}
              </div>
                <van-stepper v-model="item.num" theme="round" button-size="22" disable-input @change="onNum()" />
            </div>
          </div>
          
          <!-- 左滑删除 -->
          <template #right>
            <van-icon name="delete" class="delete-button" @click="onDelete(item)"/>
          </template>

        </van-swipe-cell>
      </div>
      <!-- 购物车end -->

    </div>
    <!-- 购物车end -->

    <!-- 结算start -->
    <van-submit-bar 
    :price="total*100"
    button-text="提交订单"
    @submit="onSubmit"
    class="settlement">
      <van-checkbox 
        v-model="allChecked" 
        checked-color="#f11a27"
        @click="onAll">
          全选
      </van-checkbox>
    </van-submit-bar>
    <!-- 结算end -->

  </div>
</template>

<script setup>
import { reactive, ref } from 'vue';
import { useRouter } from 'vue-router';

const  store = reactive([])
// 空状态
const isShow = ref(false)
const emptyStatus =()=>{ store.length==0 ? isShow.value=true : isShow.value=false }


// 进入购物车通过本地缓存中购物车里的数据渲染页面,并给每一条数据添加checked属性
const getCarts = () => {
  // 清空数据
  store.length  = 0
  let arr = JSON.parse(localStorage.getItem('carts'))
  if(arr){
    arr.forEach(el=>{
      el.checked = false
    })
    store.push(...arr)
    localStorage.setItem('carts',JSON.stringify(store))
  }
  emptyStatus()
}
getCarts()


// 全选控制单选   ref取值用value  赋值也是用value
const allChecked = ref(false)
const onAll=()=>{
  store.forEach(el=>{
    el.checked = allChecked.value
  })
  localStorage.setItem('carts',JSON.stringify(store))
  getTotal()
}


// 单选控制全选
const onChecked=()=>{
  // 商品都被选中时,全选按钮高亮
  allChecked.value = store.every(el=>{
    return el.checked
  })
  localStorage.setItem('carts',JSON.stringify(store))
  getTotal()
}


// 用户增减商品数量,更新本地存储数据
const onNum=(quantity)=>{
  localStorage.carts = JSON.stringify(store)
  getTotal()
}


// 金额计算
let total = ref(0)
const getTotal=()=>{
  // 所有被选项组成数组返回
  let userCheck=store.filter(val => {
    return val.checked == true
  });
  total.value=0
  userCheck.map(el=>{
    total.value += el.sell_price*el.num
  })
}


// 删除商品
const onDelete=(item)=>{
  store.length = 0
  let arr = JSON.parse(localStorage.getItem('carts'))
  let id = item.id
  let deleteArr = arr.filter(el=>{
    return el.id != id
  })
  store.push(...deleteArr)
  if(store.length == 0){
    allChecked.value = false
    emptyStatus()
  }
  localStorage.setItem('carts',JSON.stringify(deleteArr))
  getTotal()
}


// 提交
const router = useRouter()
const onSubmit=()=>{
  router.push('/submit')
}

</script>

<style lang="less" scoped>
.cart{
  margin: 0.3rem;
  padding: 0.05rem 0 3rem 0;
  .header{
    .manage{
      z-index: 999;
      color: #fff;
      position: fixed;
      top: 0.27rem;
      right: 0.6rem;
      font-size: 0.45rem;
      font-weight: 550;
    }
  }
  .cart_container{
    margin-top: 1.22rem;
    .list{
      position: relative;
      height: 3rem;
      border-radius: 20px;
      box-shadow: 0px 0px 5px #ccc;
      margin-bottom: 20px;
      display: flex;
      justify-content: space-around;
      align-items: center;
      .checkbox{
        position: absolute;
        top: 0.7rem;
        left: 0.1rem;
      }
      .goods_info {
        width: 7.8rem;
        height: 2rem;
        display: flex;
        justify-content: space-around;
        flex-direction: column;
        margin-left: 1rem;
        .title{
          font-size: 0.4rem;
        }
        .bottom{
          display: flex;
          justify-content: space-between;
          align-items: center;
          .price{
            color: #c82519;
            font-size: 0.45rem;
          }
        }
      }
      .delete-button {
        display: block;
        color: #c82519;
        margin-top: 0.7rem;
        margin-right: 0.1rem;
      }
      
    }
    .bottom-button {
      width: 3rem;
      height: 1rem;
    }
  }
  .settlement{
    margin-bottom: -0.1rem;
  }
}
/deep/.van-submit-bar{
  bottom:1.4rem;
}
/deep/.van-swipe-cell{
  width: 100%;
}
</style>

分模块解析:

1、单选全选

使用到了:数组方法——forEach() ,every() ,以及解构赋值(...)

(1)单选逻辑——选中购物车中当前商品

0、总体逻辑:为本地缓存中的数据添加checked属性

1、复选框根据:name="item"进行渲染;

2、使用 v-model 进行双向数据绑定。商品的checked属性为true时,选框选中;

3、定义全局变量store,存放本地缓存中的数据,store应为响应式;

4、定义getCarts函数

        (1)将本地缓存中的数据放到数组arr中,注意要JSON.parse();

        (2)如果本地缓存的购物车里有数据,即arr中有值——使用forEach()对arr进行遍历,为每一件商品添加checked属性,初始值为false(未选中);

        (3)解构arr,由数组变成一个一个的对象,并push到store容器中;

        (4)更新本地缓存

5、调用空状态函数emptyStatus(),如果本地缓存的购物车里没有数据,就显示空状态;

6、在setup中调用getCarts(),使checked属性得到渲染

HTML结构:

<!-- 单选选框 -->
<div v-for="(item,index) in store" :key="index" class="list">
  <div class="checkbox">
    <van-checkbox
    :name="item" 
    v-model="item.checked"
    @change=onChecked
    checked-color="#f11a27"
    ></van-checkbox>
  </div>
</div>

JS代码:

// 单选按钮
const store = reactive([])

// 进入购物车时,通过本地缓存中购物车里的数据渲染页面,并给每一条数据添加checked属性
const getCarts = () => {
  // 清空store
  store.length  = 0
  let arr = JSON.parse(localStorage.getItem('carts'))
  if(arr){
    arr.forEach(el=>{
      el.checked = false
    })
    store.push(...arr)
    localStorage.setItem('carts',JSON.stringify(store))
  }
  emptyStatus()
}
getCarts()

 (2)全选逻辑--全选控制单选,选中购物车中所有内容

0、总体逻辑:使全选的值与每一个单选的值相同

1、在全选选框中添加     @click="onAll"     点击事件;

2、使用 v-model 进行双向数据绑定。allChecked初始值为 false ,使用了ref,后续对allChecked赋值的时候,需要用到allChecked.value;

3、在onAll()函数中,使用forEach()遍历store中的商品数据,给每一件商品的 checked属性赋值——当allChecked.value = true时,每一件商品的checked属性也为true;反之,全选选框未勾选,即allChecked.value = false时,每一件商品的checked属性也为false;

4、调用金额结算函数。

HTML结构:

<!-- 结算start -->
<van-submit-bar 
:price="total*100"
button-text="提交订单"
@submit="onSubmit"
class="settlement">
  <van-checkbox 
    checked-color="#f11a27"
    v-model="allChecked" 
    @click="onAll">
      全选
  </van-checkbox>
</van-submit-bar>
<!-- 结算end -->

JS代码:

// 全选控制单选   ref取值用value  赋值也是用value
const allChecked = ref(false)
const onAll=()=>{
  store.forEach(el=>{
    el.checked = allChecked.value
  })
  localStorage.setItem('carts',JSON.stringify(store))
  getTotal()
}

(3)单选控制全选——购物车中所有商品均被选中,全选按钮也被选中

0、总体逻辑:用every()遍历本地缓存中的数据,当所有的checked属性均为true时,全选也为true

1、在单选选框中添加     @change=onChecked     事件;

2、使用every()遍历store,返回值是boolean,如果每个商品都被选中,every返回true,有一个商品没有被选中,则返回false,将其赋值给allChecked.value(控制全选是否高亮的值);

4、调用金额结算函数。

HTML结构:

<!-- 单选选框 -->
<div v-for="(item,index) in store" :key="index" class="list">
  <div class="checkbox">
    <van-checkbox
    :name="item" 
    v-model="item.checked"
    @change=onChecked
    checked-color="#f11a27"
    ></van-checkbox>
  </div>
</div>


<!-- 结算start -->
<van-submit-bar 
:price="total*100"
button-text="提交订单"
@submit="onSubmit"
class="settlement">
  <!-- 全选选框 -->
  <van-checkbox 
    v-model="allChecked" 
    checked-color="#f11a27"
    @click="onAll">
      全选
  </van-checkbox>
</van-submit-bar>
<!-- 结算end -->

JS代码:

// 单选控制全选
const onChecked=()=>{
  // 商品都被选中时,全选按钮高亮
  allChecked.value = store.every(el=>{
    return el.checked
  })
  getTotal()
}

2、数量加减——改变数量,同时商品金额动态改变

0、总体逻辑:本质是商品中 num 值的改变和简单的数学运算;

1、用户增减商品数量,更新本地存储数据;

2、调用getTotal()计算金额

HTML结构:

<div v-for="(item,index) in store" :key="index" class="list">
    <van-stepper v-model="item.num" @change="onNum"/>
</div>

JS代码:

// 用户增减商品数量,更新本地存储数据
const onNum=()=>{
  localStorage.carts = JSON.stringify(store)
  getTotal()
}

3、金额计算

0、总体逻辑:过滤出被选中的商品,清空总价,计算总价(+=)

1、由变量total的值来确定商品价格price;

2、由于组件中存在固定单位,商品价格应该*100;

3、filter()过滤出用户选择的商品,返回数组;

4、价格先清零,再进行计算,否则将保留原先计算出的价格;

5、使用map()对数组中每一个商品的价格进行计算,注意要使用 += 赋值给total.value;

6、在单选全选,数量计算中调用价格计算的函数,确保每次操作都重新计算价格

HTML结构:

<!-- 结算start -->
<van-submit-bar 
    :price="total*100"
    button-text="提交订单"
    @submit="onSubmit"
    class="settlement"
>
</van-submit-bar>
<!-- 结算end -->

JS代码:

// 金额计算
let total = ref(0)
const getTotal=()=>{
  // 所有被选项组成数组返回
  let userCheck=store.filter(val => {
    return val.checked == true
  });
  total.value=0
  userCheck.map(el=>{
    total.value += el.sell_price*el.num
  })
}

4、空状态

购物车内没有商品的时候显示,主要在 进入购物车删除购物车内所有的商品 时调用

HTML结构:

<!-- vant空状态 -->
<van-empty v-show="isShow" description="购物车目前还没有商品" image="https://img.yzcdn.cn/vant/custom-empty-image.png">
   <router-link to="/goods">
    <van-button round type="danger" class="bottom-button">
      去购物
    </van-button>
   </router-link> 
  </van-empty>
<!-- 空状态end -->

JS代码:

// 空状态
const isShow = ref(false)
const emptyStatus =()=>{ store.length==0 ? isShow.value=true : isShow.value=false }

5、左滑删除

0、总体逻辑:(1)把数据从缓存拿出来;(2)过滤删除数据;(3)存储最新数据

1、清空store容器中的商品数据

2、过滤已经删除的商品数据,将没有删除的商品数据,组成数组返回;

3、将现存的商品数据push到store容器中;

4、如果用户把商品数据都删了,全选按钮要取消勾选,同时显示空状态

5、结算

HTML结构:

<!-- 左滑删除 -->
<template #right>
    <van-icon name="delete" class="delete-button" @click="onDelete(item)"/>
</template>

JS代码:

// 删除商品
const onDelete=(item)=>{
  store.length = 0
  let arr = JSON.parse(localStorage.getItem('carts'))
  let id = item.id
  let deleteArr = arr.filter(el=>{
    return el.id != id
  })
  store.push(...deleteArr)
  if(store.length == 0){
    allChecked.value = false
    emptyStatus()
  }
  localStorage.setItem('carts',JSON.stringify(deleteArr))
  getTotal()
}

6、结算跳转

路由跳转

HTML结构:

<!-- 结算start -->
<van-submit-bar 
    :price="total*100"
    button-text="提交订单"
    @submit="onSubmit"
    class="settlement"
>
</van-submit-bar>
<!-- 结算end -->

JS代码:

// 提交结算
const router = useRouter()
const onSubmit=()=>{
  router.push('/submit')
}


网站公告

今日签到

点亮在社区的每一天
去签到