Vue3+TS+移动端-购物车实现详细步骤+项目优化

分析得到:因为购物车,在几个页面都是需要进行数据互通,主页面,商品页面,详情页面,三个不同的组件,要实现一个页面数据变化,另外页面数据跟着变化,那必须要使用vue中vuex,因为是vue3也可以使用pinia

vuex官网:https://vuex.vuejs.org/zh/

pinia官网:https://pinia.web3doc.top/

这次购物车就选用vuex:

第一步:需要配置自动导入

在vite.config.ts中配置

第二步: 修改store-->index.ts 要实现模块化开发

注意:建立好模块之后,index.ts需要引入

第三步: 配置完成之后,需要重启项目,一定要重新启动

第四步:还需要下载依赖,配置vuex数据持久化存储

vuex的特点是: 全局变量,

他有一个缺点: 如果页面刷新,那我们做的全局变量会初始化

怎么解决这个问题:

用的底层原理就是将 vuex 的全局变量放到 localstorage

localstorage,生命周期,您不删除的话,他不会删除

sessionstorage 生命周期,浏览器关闭了,就会自动删除

官方: 持久化插件

vuex刷新之后他的数据初始化的问题.

用的是持久化插件

下载vuex数据持久化的插件

     npm   i  [email protected] --save

或者 :

    cnpm   i  [email protected] --save

第五步: 配置插件,在index.ts文件中配置,数据持久存储

 完整代码段:

整个代码
import { createStore } from 'vuex'
import cart from "./modules/cart"
import createPersistedState from "vuex-persistedstate";

export default createStore({

  modules: {
    cart
  },
  plugins: [createPersistedState({
    //指定数据被存储在哪里,当值为window.localStorage则表示存储在localStorage中,
    // 当值为window.sessionStorage则表示存储在sessionStorage中
    storage: window.localStorage,
    key: 'sellcard',
    paths: ["cart"]
  })],
})

最后:项目准备工作已经完成了,所有的配置已经完成,接下来就是写代码,实现购物车的业务逻辑

购物车业务逻辑部分:

第一步:在全局变量中定义变量

首先要确定什么类型,是数组,对象,还是字符串,因为是购物车,有很多商品,商品包括名字,价格,数量等.肯定是数组比较合适

 state: {
   // 放全局变量的
   // 定义一个数组存入 你往购物车添加的所有商品
    cartList: []
  },

第二步: 添加购物车的点击事件

添加购物车,需要进行传参,把整个数据传过去

// vue2中store 使用this.$store 因为他是全局挂载
// vue3中store 是按需导入的 不能使用this.$store
// vue3中 let store = new useStore()
// vue3语法糖中 new 不要
// let  store = useStore()
let store = useStore();

//第一个方法是把商品添加到购物车
let addToCart = (food: any) => {
  //这个方法要操作 全局变量
  console.log(food);
  store.commit("setData", food);
};

第三步: 在store的mutations里面设置一个方法

设置这个方法主要是修改改变state中的数据

 mutations: {
        //同步的修改 state的值的方法
        setData(state: any, foodobj: any) {
            // foodobj
            // 没有点餐的数量 要呀
            // 你在点击添加商品的时候.相当于把商品添加进来,然后
            // 数量默认为1
            state.cartList.push({ count: 1, ...foodobj })
        }
    },

第四步: 点击添加购物车案例

小bug出现:点击购物车,跳转到详情页面去了,主要是事件冒泡,需要阻止事件冒泡

第五步: 实时的更新 商品的状态

主要是解决:有数量的时候显示数据,如果数量为0,显示"添加购物车"

 v-if和v-else进行判断

 难点:关键是怎么判断,到底什么时候v-if,什么时候v-else呢

问题:

//他不是点击触发出的点击事件
//详情页面也有一个添加购物车
//我点击详情页面的添加购物车,
//商品的按钮就会消失
//因为我已经添加了购物车

解决思路:vue中可以用监听的方式来实时掌握数据源的变化,当数据源发生了变化,就触发这个v-if或者v-else;而且它们返回的true或者false

1.可以用computed实时监听数据源的变化,但是需要传参过去

注意:但是我们需要进行传参,然而计算属性不能传值,用的办法就是返回一个函数,因为函数是可以进行接受传参的,可以解决这个不能传参的问题

 let isHaveFood = computed(() => {
    let fn = (id: any) => {
      //因为v-if最终的结果为true /false
      // 我这里的方法会返回一个true /false
      // 根据数据源的变化而变化
      // 这个数据源在 全局变量中
      // 实时的监听全局变量中的cartList的变化
      //store.getters
      return store.getters.isFood(id);
    };
    return fn;
  });

2.在 getters:中定义,因为getters可以计算数据源的变化情况,但是也是需要返回一个函数,因为计算属性不能传参,返回函数来接收computed传的参数id

// 全局变量中的计算属性
    // 计算属性不能传值,只能返回一个函数才可以传值
    // 主要是判断变量中的id和传过来的id是否相同
    isFood(state: any) {
      return function (id: number) {
        for (let i = 0; i < state.cartList.length; i++) {
          if (state.cartList[i].id == id) {
            return true;
          }
        }
        return false;
      };
    },

3.在getters中实时监听计算state中的数据源,就可以判断是否被添加到购物车了,主要是利用循环,判断每一项,数据源的商品id是否等于computed传过来的id,如果相同就说明添加了购物车,此时就显示数量,否则显示"添加购物车"

第六步: 获取数据,显示数据量,还是添加购物车

1.在getters定义方法,获取加入购物车的数量

 //得到当前加减数量
    getCount(state: any) {
      return function (id: number) {
        for (let i = 0; i < state.cartList.length; i++) {
          if (state.cartList[i].id == id) {
            return state.cartList[i].count; //返回数量
          }
        }
        return 1;
      };
    },

2.主要还是判断computed计算属性的参数和数据源的id是都相等

  //获取数量
  let getCount = computed(() => {
    return function (id: any) {
      return store.getters.getCount(id);
    };
  });

第七步: 实现加减数量的变化

 1.给加减号添加点击事件,定义一个方法

 // 给 加减号添加点击事件
<div>
      <van-button size="mini" @click="updCount('+',ele.id)">+</van-button>
                  {
   
   { getCount(ele.id) }}
      <van-button size="mini" @click="updCount('-',ele.id)">-</van-button>
 </div>

 2.编写代码逻辑,但是要注意的是,mutations里面只能接受两个参数,但是我们要传递三个参数,此时用对象

// 在goods.vue中编写方法
// fh 符号  id就是商品的id
let  updCount = (fh,id)=>{
    let obj:Object = {
         fh,
         id
    }
    store.commit("updCount",obj)
}

3.在ts中编写代码

主要是利用循环遍历,state中每一项,判断我们传过去的id和实际数据源中的id是否一样;如果是加号就直接进行数量上相加,主要是当减法的时候,需要再做判断

 // 购物车加减
    updCount(state: any, obj: { fh: string; id: number }) {
      for (let i = 0; i < state.cartList.length; i++) {
        if (state.cartList[i].id == obj.id) {
          if (obj.fh == "+") {
            state.cartList[i].count++;
          } else {
            // 需要判断
            if (state.cartList[i].count > 1) {
              state.cartList[i].count--;
            } else {
              // 如果减到0 将这个商品全局变量中删除 不能在我们购物车中显示了
              state.cartList.splice(i, 1);
              // 如果splice有2个参数的话,表示从i开始,一共删除几个元素
            }
          }
        }
      }
    },

注意:如果数量此时已经不大于1了, 我们就要将这个商品在全局变量中删除,不能在购物车里显示,数组的方法,我们可以用splice,两个参数,第一个代表从i开始,第二个代表删除几个元素.

第八步:购物车弹框显示,已经添加到购物车的商品

1.在对应vant组件里面找模板,添加购物车,是在我们layout页面进行布局,因为商品组件,也要显示

<div class="footerbox">
    <van-submit-bar :price="12312" button-text="去结算">
      <van-action-bar-icon icon="cart-o" badge="5" size="large" @click="show = !show" />
    </van-submit-bar>

    <!--    // show其实就是一个开关 肯定是一个变量 那就要在js中定义 -->
    <van-action-sheet v-model:show="show" title="标题">
      <div class="content">内容</div>
    </van-action-sheet>
  </div>


js中

定义一个变量
// false 代表隐藏  true 代表的是显示

let show = ref(false)

2.我们需要定义一个方法,控制,点击按钮是否显示与隐藏

第九步:显示已选中的商品

问题:怎么去获取state中的值,这里面就是添加购物的商品

1.还是需要用getters来获取

   // 这个是获取购物车中的list中数据
    getCartList(state: any) {
      return state.cartList;
    },

2.用computed计算属性实时监听数据的变化,而且它还有缓存功能

  let getCartList = computed(() => {
    return store.getters.getCartList;
  });

3.页面上显示但是会报错 getCount  updCount 它们在goods.vue写过一次又要用, 复制粘贴过来

页面上使用
 <van-card
          v-for="(ele, i) in getCartList"
          :key="i"
          :price="ele.price.toFixed(2)"
          :desc="ele.goodsDesc"
          :title="ele.name"
          :thumb="ele.imgUrl"
        >
          <template #footer>
            <div>
              <van-button size="mini" @click="updCount('+', ele.id)">+</van-button>
              {
   
   { getCount(ele.id) }}
              <van-button size="mini" @click="updCount('-', ele.id)">-</van-button>
            </div>
          </template>
        </van-card>

最后一步:计算总数量和总价格

1.触发点也是数据源的改变而触发 ,cartList数据改变,他就要触发

    // 总价格和总数量
    getTotal(state: any) {
      let totalNumber: number = 0;
      let totalPrice: number = 0;
      // 循环把数量加起来 数量乘以价格
      for (let i = 0; i < state.cartList.length; i++) {
        totalNumber += state.cartList[i].count;
        totalPrice += state.cartList[i].price * state.cartList[i].count;
      }

      return {
        totalNumber,
        totalPrice: totalPrice * 100, //还需要乘以100方便数据显示
      };
    },
  },


  // 获取总数量和总价格
  let getTotal = computed(() => {
    return store.getters.getTotal;
  });

2.页面上直接渲染即可

 最后总结:

1.其实里面很多方法,写起来非常的冗余,两个页面重复的代码比较多,这样会造成性能下限,资源浪费,所以我们可以把公共的代码提取出来

2.mixin他的作用就是可以把公共的方法提出来

第一步:

src中新建mixin的目录

第二步:

在mixin的目录中新建一个文件 cartMixin.ts

把公共的方法提出来

 第三步:完整代码块

export default function () {
  let store = useStore();
  let getCartList = computed(() => {
    return store.getters.getCartList;
  });

  // 获取总数量和总价格
  let getTotal = computed(() => {
    return store.getters.getTotal;
  });

  //第一个方法是把商品添加到购物车
  let addToCart = (food: any) => {
    //这个方法要操作 全局变量
    // console.log(food);
    store.commit("setData", food);
  };

  //他不是点击触发出的点击事件
  //详情页面有一个添加购物车
  //我点击详情页面的添加购物车,
  //商品的按钮就会消失
  //因为我已经添加了购物车
  // 用什么方法去触发这个方法了
  // 计算属性 具有监听的效果
  // 当数据源改变的时候就会触发
  // 计算属性能传值吗?
  // 计算属性在vue中当基本属性使用
  let isHaveFood = computed(() => {
    let fn = (id: any) => {
      //因为v-if最终的结果为true /false
      // 我这里的方法会返回一个true /false
      // 根据数据源的变化而变化
      // 这个数据源在 全局变量中
      // 实时的监听全局变量中的cartList的变化
      //store.getters
      return store.getters.isFood(id);
    };
    return fn;
  });

  //获取数量
  let getCount = computed(() => {
    return function (id: any) {
      return store.getters.getCount(id);
    };
  });

  //加或者减
  //fh符号
  let updCount = (fh: string, id: any) => {
    // 因为加减是点击触发
    // store中mutations去写方法
    //mutations中的方法只有两个参数
    // 第一个参数为state 第二个参数就是你传过去的
    //我们有两个,怎么才能变成一个
    let obj: Object = {
      fh,
      id,
    };
    store.commit("updCount", obj);
  };
  // 把方法暴露出去
  return {
    updCount,
    getCount,
    isHaveFood,
    addToCart,
    getTotal,
    getCartList,
  };
}

第四步:怎么在页面上用,按需引入即可使用

import  cartMixin from "@/mixin/cartMixin.ts"
let { updCount,  getCount, isHaveFood,addToCart,getTotal ,getCartList }  =  cartMixin()
cartMixin是一个方法 用的时候需要添加括号  cartMixin()

cartMixin() 代表的是调用这个方法  这个方法他又返回一个对象

````js

最后的最后:两个页面完整的代码复制在下面:

商品页面完整代码:

<template>
  <div class="goodsbox">
    <div class="leftbox">
      <div>
        <div :class="['nav', activeIndex == index ? 'active' : '']" v-for="(item, index) in data.goodsList" :key="index"
          @click="toRight(index)">
          {
   
   { item.name }}
        </div>
      </div>
    </div>
    <div class="rightbox">
      <div>
        <div class="card" v-for="(i, e) in data.goodsList" :key="e" :id="'div' + e">
          <div class="rightTitle">{
   
   { i.name }}</div>
          <van-card v-for="(ele, index) in i.foods" :key="index" :num="ele.sellCount" :price="ele.price.toFixed(2)"
            :desc="ele.goodsDesc" :title="ele.name" :thumb="ele.imgUrl" @click="toDetail(ele)">
            <!-- click-thumb 不给父级加 给这个图片加 然后跳转到详情 -->
            <template #tags>
              <span> 月售{
   
   { ele.sellCount }} </span>
              <span><van-rate v-model="ele.rating" :size="18" color="#ffd21e" void-icon="star" void-color="#eee"
                  readonly />
              </span>
            </template>
            <template #footer>
              <template v-if="isHaveFood(ele.id)">
                <div>
                  <van-button size="mini" @click.stop="updCount('+', ele.id)">+</van-button>
                  {
   
   { getCount(ele.id) }}
                  <van-button size="mini" @click.stop="updCount('-', ele.id)">-</van-button>
                </div>
              </template>
              <van-button icon="plus" type="danger" v-else size="mini" round
                @click.stop="addToCart(ele)">添加购物车</van-button>
            </template>
          </van-card>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import BetterScroll from 'better-scroll'
import { api_goodsList } from '../../api/home';
import { GoodsEntity } from '../../api/model/GoodsEntity';
import cartMixin from "../../mixin/cartMixin"
// 定义左侧右则滚动 放到全局作用域
let leftBScroll: BetterScroll;
let rightBScroll: BetterScroll;
// 定义一个数据源
let data = reactive(new GoodsEntity())

// 定义一个方法 可以不在onMounted中发请求
let queryGoodsList = async () => {
  let res: any = await api_goodsList()
  // console.log(res)
  // 把拿到的值给自己定义的赋值
  data.goodsList = res.data

  nextTick(() => {
    // 参数1是要滚动的元素  参数2是配置项
    // as是原生js定义类型
    leftBScroll = new BetterScroll(document.querySelector(".leftbox") as any, {
      click: true,//允许滚动区域的选项可以点击
      // disableMouse: true, //启用鼠标滚动
      // disableTouch: true,  //启用手指触摸
    })
    rightBScroll = new BetterScroll(document.querySelector(".rightbox") as any, {
      click: true,//允许滚动区域的选项可以点击
      probeType: 3,
      // disableMouse: true, //启用鼠标滚动
      // disableTouch: true,  //启用手指触摸
      // probeType: 3 //决定是否派发 scroll 事件
      // 1. probeType 为 0,在任何时候都不派发 scroll 事件,
      // 2. probeType 为 1,仅仅当手指按在滚动区域上,每隔 momentumLimitTime 毫秒派发一次 scroll 事件,
      // 3. probeType 为 2,仅仅当手指按在滚动区域上,一直派发 scroll 事件,
      // 4. probeType 为 3,任何时候都派发 scroll 事件,包括调用 scrollTo 或者触发 momentum 滚动动画
    })
    // 正在滚动
    rightBScroll.on("scroll", (val: any) => {
      // val有2个值,就是滚动的高度
      // console.log(val);
      // Math.abs取绝对值 就是正值
      let height = Math.abs(val.y);
      // 得到滚动的距离
      // 在正在滚动里面调用
      // console.log(rightHeight.value)
      for (let i = 0; i < rightHeight.value.length; i++) {
        // 判断正在滚动的高度和实时监听的开始高度和结束高度
        if (height >= rightHeight.value[i].startHeight && height <= rightHeight.value[i].endHeight) {
          activeIndex.value = i;
          // 提高性能
          break; //结束循环
        }
      }
    })
  })
}
// 第三步算每一个div的区域
// 需要获取拿到三个值
// 需要实时监听 而且需要缓存 当数据源发生改变的时候,才会触发
let rightHeight = computed(() => {
  let newArray = data.goodsList.map((ele, index) => {
    // 获取右则的dom元素
    let dom: any = document.querySelector("#div" + index)//做高亮使用
    let startHeight = dom.offsetTop;//开始高度
    let endHeight = dom.offsetTop + dom.offsetHeight;//结束高度
    return { startHeight, endHeight, index }
  })
  return newArray //计算属性必须有返回值
})
// diao用方法
queryGoodsList();
//点击去高亮去右则
let activeIndex: any = ref(0)//默认第一个高亮
function toRight(index: number) {
  // 通过下标点击左侧对应右则
  // 先做左侧高亮 就是点击谁 谁添加类名active
  activeIndex.value = index;
  // el要谁显示在第一个位置的dom元素
  // time 速度 单位为毫秒
  // x x轴偏移量
  // easing 速度曲线  匀速
  let dom: any = document.querySelector("#div" + index)
  // console.log(dom)
  let eas: any = "easing"
  rightBScroll.scrollToElement(dom, 3000, 0, -8, eas)
}
// 点击去详情
// food类型就是我们定义的Foods
// router和route是全局变量
let router = useRouter();//语法糖不需要new
function toDetail(food: any) {
  // 编程式路由
  router.push({
    path: "/goodsDetail",
    // query: food,
    query: {
      food: JSON.stringify(food)//需要深拷贝 因为拿到的值 数据只显示object
    },
  })
  // router.push({
  //   name: "goodsDetail",
  //   params: food,
  //   // params: {
  //   //   food: JSON.stringify(food)//需要深拷贝 因为拿到的值 数据只显示object
  //   // },
  // })
}
// 购物车开始
// vue3中store用之前需要引入
// let store = useStore();
// function addToCart(food: any) {
// store.commit("setData", food);
// }
let { updCount,
  getCount,
  isHaveFood,
  addToCart,
} = cartMixin()
// // 他不是点击触发的点击事件
// // 详情页面也有添加购物车
// // 点击了详情按钮就会消失 计算属性具有监听的效果
// let isHaveFood = computed(() => {
//   // vue中计算属性不能传值  返回一个函数就可以传值
//   return function (id: any) {
//     // 因为v-if最终结果为true/false
//     // 这里的方法返回一个true或者false
//     // 通过false或者true判断添加购物车还是+ - 号
//     // false或者true这个数据源在cartList
//     // store.getters
//     return store.getters.isFood(id);
//   }
// })
// //得到当前加减数量 也要实时监听
// let getCount = computed(() => {
//   return function (id: any) {
//     return store.getters.getCount(id);
//   }
// })
// // 加减 fh代表是符号
// let updCount = (fh: string, id: any) => {
//   // 因为mutations只能传2个参数
//   // 但是我们要传三个 只能定一个对象
//   let obj: any = {
//     fh,
//     id,
//   }
//   store.commit("updCount", obj)
// }
</script>

<style scoped lang="scss">
.goodsbox {
  width: 100%;
  height: 100%;
  display: flex;

  .leftbox {
    flex: 0 0 130px;
    height: 100%;
    background-color: rgb(229, 236, 197);
    overflow-y: auto;

    .nav {
      height: 50px;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }

  .rightbox {
    flex: 1;
    height: 100%;
    background-color: rgb(193, 227, 225);
    overflow-y: auto;

    // overflow: hidden;
    .rightTitle {
      margin-top: 5px;
    }
  }

  .active {
    color: #fff;
    background: #f00;
  }
}
</style>

Layout页面完整代码:

<template>
  <div class="layoutheader">
    <comm-header></comm-header>
  </div>
  <div class="navbox">
    <van-tabs v-model:active="activeName" color="orange" title-active-color="#f00">
      <!-- name一般就是路由 -->
      <van-tab title="商品" name="/home/goods" to="/home/goods"></van-tab>
      <van-tab title="评价" name="/home/ratings" to="/home/ratings"></van-tab>
      <van-tab title="店铺" name="/home/shop" to="/home/shop"></van-tab>
    </van-tabs>
  </div>
  <div class="content">
    <router-view></router-view>
  </div>
  <div class="footerbox">
    <van-submit-bar :price="getTotal.totalPrice" button-text="去结算" @click="show = !show"
      style="z-index: 2100;background-color: orange;">
      <van-action-bar-icon icon="cart-o" :badge="getTotal.totalNumber" />
    </van-submit-bar>
    <!-- 底部弹出层 -->
    <van-action-sheet v-model:show="show" title="已加入的商品">
      <div class="content">
        <van-card v-for="(ele, i) in getCartList" :key="i" :price="ele.price.toFixed(2)" :desc="ele.goodsDesc"
          :title="ele.name" :thumb="ele.imgUrl">
          <template #footer>
            <div>
              <van-button size="mini" @click="updCount('+', ele.id)">+</van-button>
              {
   
   { getCount(ele.id) }}
              <van-button size="mini" @click="updCount('-', ele.id)">-</van-button>
            </div>
          </template>
        </van-card>
      </div>
    </van-action-sheet>
  </div>
</template>

<script lang="ts" setup>
import commHeader from "../../components/commHeader/index.vue";
import cartMixin from "../../mixin/cartMixin"

// 初始值
const activeName = ref('/home/goods');
// 小bug 路由没用动 但是页面有一个初始值
// 实时监听临时路由地址的变化
// vue3中没有this.route 需要引入 已经自动导入
let route = useRoute()
watch(route, (n, o) => {
  // 把新值赋值给路由
  activeName.value = n.path
}, {
  deep: true,
  immediate: true,
})
// 开关 默认是隐藏状态
let show = ref(false)
// 实时监听计算属性中的数据变化
// 实时监听数据源的变化
// 计算属性 必须有返回值
let { updCount,
  getCount,
  getTotal,
  getCartList, } = cartMixin()
</script>

<style lang="scss" scoped>
.layoutheader {
  height: 150px;
}

.navbox {
  height: 45px;
}

.content {
  // 高度要减去上面导航和头部的高度 中间要加空格
  height: calc(100% - 195px - 50px);
}

.footerbox {
  height: 50px;
}

::v-deep .van-action-bar-icon__icon {
  font-size: 26px;
}

::v-deep .van-popup {
  height: 250px;
  padding-bottom: 50px;
}

.van-action-bar-icon {
  background-color: orange;
}
</style>

store下cart.ts完成代码:

export default {
  state: {
    // 全局变量
    cartList: [], //定义一个数组,存你往购物车添加的所有商品
  },
  getters: {
    // 全局变量中的计算属性
    // 计算属性不能传值,只能返回一个函数才可以传值
    // 主要是判断变量中的id和传过来的id是否相同
    isFood(state: any) {
      return function (id: number) {
        for (let i = 0; i < state.cartList.length; i++) {
          if (state.cartList[i].id == id) {
            return true;
          }
        }
        return false;
      };
    },
    //得到当前加减数量
    getCount(state: any) {
      return function (id: number) {
        for (let i = 0; i < state.cartList.length; i++) {
          if (state.cartList[i].id == id) {
            return state.cartList[i].count; //返回数量
          }
        }
        return 1;
      };
    },
    // 这个是获取购物车中的list中数据
    getCartList(state: any) {
      return state.cartList;
    },
    
    // 总价格和总数量
    getTotal(state: any) {
      let totalNumber: number = 0;
      let totalPrice: number = 0;
      // 循环把数量加起来 数量乘以价格
      for (let i = 0; i < state.cartList.length; i++) {
        totalNumber += state.cartList[i].count;
        totalPrice += state.cartList[i].price * state.cartList[i].count;
      }

      return {
        totalNumber,
        totalPrice: totalPrice * 100, //还需要乘以100方便数据显示
      };
    },
  },
  mutations: {
    // 同步的修改state的值的方法
    setData(state: any, foodObj: any) {
      // 要不加的数据追加到变量中
      state.cartList.push({ count: 1, ...foodObj });
    },
    // 购物车加减
    updCount(state: any, obj: { fh: string; id: number }) {
      for (let i = 0; i < state.cartList.length; i++) {
        if (state.cartList[i].id == obj.id) {
          if (obj.fh == "+") {
            state.cartList[i].count++;
          } else {
            // 需要判断
            if (state.cartList[i].count > 1) {
              state.cartList[i].count--;
            } else {
              // 如果减到0 将这个商品全局变量中删除 不能在我们购物车中显示了
              state.cartList.splice(i, 1);
              // 如果splice有2个参数的话,表示从i开始,一共删除几个元素
            }
          }
        }
      }
    },
  },
  actions: {
    // 异步方法 可以修改state
  },
};

样式展示:

猜你喜欢

转载自blog.csdn.net/shi15926lei/article/details/128251376