ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【Vue项目】尚品汇(六)ShopCar组件开发 购物车模块

2022-09-03 18:00:46  阅读:181  来源: 互联网

标签:skuId Vue uuid skuNum 尚品 购物车 disNum store


4 购物车

4.1 购物车商品数量控制

Detail\index.vue

            <div class="cartWrap">
              <div class="controls">
                <input v-model="skuNum" @change="changeSkuNum" autocomplete="off" class="itxt">
                <a href="javascript:" class="plus">+</a>
                <a href="javascript:" class="mins">-</a>
              </div>
              <div class="add">
                <a href="javascript:">加入购物车</a>
              </div>
            </div>
    // 商品数量
    changeSkuNum(event) {
      let value = event.target.value * 1
      if(isNaN(value) || value < 1 || value > 999) {
        console.log('非法数据')
      } else {
        this.skuNum = parseInt(value)
      }
    },

通过* 1的方式判断是否输入为非数字,因为非数字乘1的话会变为undefined

4.2 购物车路由跳转

分析:添加购物车需要两个数据:sku_num和sku_id,服务器返回的数据只是成功或者失败不会返回其他信息。

  • 编写api
// api/cart/addToCart/{ skuId }/{ skuNum }
export const reqAddOrUpdateShopCar = (skuId, skuNum) => {
    return requests({
        url:`/cart/addToCart/${skuId}/${skuNum}`,
        method: 'post'
    })
}
  • vuex编写actions
const actions = {
    async getDetailInfo(context, skuId) {
        let result = await reqGetDetailInfo(skuId);
        if(result.code === 200) {
            context.commit('GETDETAILINFO', result.data);
        }
    },
    async addOrUpdateShopCar({context}, {skuId, skuNum}) {
        let result = await reqAddOrUpdateShopCar(skuId, skuNum)
        if(result.code === 200) {
            return 'ok';
        } else {
            return Promise.reject(new Error('fail'));
        }
    }
}

不需要再写mutations和state仓库了,因为没有返回数据

后面请求头写完uuid后会产生数据

  • 编写路由信息
    {
        path: '/addShopCarSuccess',
        component: AddCartSuccessrt,
        name: 'addShopCarSuccess',
        meta: {
            showFooter: true
        }
    }
  • 根据返回的结果进行响应路由跳转
    // 购物车添加
    async addShopCar() {
      try{
        await this.$store.dispatch('addOrUpdateShopCar', {
          skuId : this.skuInfo.id,
          skuNum : this.skuNum
        });
        this.$router.push({name: 'addShopCarSuccess'})// 路由跳转
      } catch (error) {
        alert(error.message)
      }
    }

4.3 路由传参结合回话存储传递数据

分析:H5新增的两种存储:本地存储(localstorage)会话存储(sessionstorage),这里应该使用sessionstorage,因为vue是单页面应用到网页关闭只有一个会话。可以使用路由query传递skuNum而用sessionstorage存储skuInfosquSaleAttrList

  • 将信息存入sessionstorage

Detail/index.vue

// 购物车添加
    async addShopCar() {
      try{
        await this.$store.dispatch('addOrUpdateShopCar', {
          skuId : this.skuInfo.id,
          skuNum : this.skuNum
        });
        // 路由跳转
        this.$router.push({name: 'addShopCarSuccess', query:{skuNum: this.skuNum}})
        sessionStorage.setItem('skuInfo', JSON.stringify(this.skuInfo))
        sessionStorage.setItem('spuSaleAttrList', JSON.stringify(this.spuSaleAttrList))

      } catch (error) {
        alert(error.message)
      }

    }

4.4 请求头加入uuid判断游客身份

分析:可以在本地存储localstorage设置一个uuid,然后每次请求都携带这个uuid,后端就能通过这个uuid在不登录的情况下判断用户返回相应的数据了。那么首先这个uuid应该存储在store仓库中,然后需要一个接口函数能够判断localstorage中有没有uuid,如果没有则创建有则直接返回仓库,最后也是最重要的一步,应该在请求拦截器中的config参数设置uuid,如此发出的请求就能携带uuid了。

  • 编写uuid生成接口 \utils\uuid_token.js
import { v4 as uuidv4 } from 'uuid';

export const getUUID = () => {
    let uuid_token = localStorage.getItem('UUID_TOKEN')
    if(uuid_token) {
        return uuid_token
    }
    uuid_token = uuidv4()
    localStorage.setItem('UUID_TOKEN', uuid_token)
    return uuid_token
}
  • 在vuex仓库中生成uuid \store\detail\index.js
import {getUUID} from '@/utils/uuid_token'
const state = {
    detailInfo: {},
    uuid_token: getUUID()
}

随便找一个模块仓库放就可以

  • 在请求拦截器中config添加携带仓库中的uuid
import store from '@/store'
// 请求拦截器,在请求发出之前能够检测到,做一些指定的业务
requests.interceptors.request.use((config)=>{
    // console.log(store.state.detail.uuid_token)
    nprogress.start();
    // 参数为config的回调函数
    // config为配置对象,包含一个中要的属性headers请求头
    if(store.state.detail.uuid_token) {
        config.headers.userTempId = store.state.detail.uuid_token
    }
    return config;
});

userTempId为前后端协商的字段不可修改

再次进入购物车页面,可以看到购物车接口可以返回之前加入购物车的数据了。

注意是购物车页面,添加购物车页面是不返回任何数据的

4.5 更新购物车商品数量

更新的接口和添加的结构是相同的,只是,num为负数表示减少为正数表示添加。

export const reqAddOrUpdateShopCar = (skuId, skuNum) => {
    return requests({
        url:`/cart/addToCart/${skuId}/${skuNum}`,
        method: 'post'
    })
}

其他没有特别的点,记得发完请求之后再重新获取下页面参数

          <li class="cart-list-con5">
            <a @click="skuNumHandler('minus', cartInfo, -1)"   class="mins">-</a>
            <input autocomplete="off" type="text" @change="skuNumHandler('change', cartInfo, $event.target.value * 1)" :value="cartInfo.skuNum"  minnum="1" class="itxt">
            <a @click="skuNumHandler('add', cartInfo, 1)"  class="plus">+</a>
          </li>
    methods: {
      getData() {
        this.$store.dispatch('getCarList')
      },
      async skuNumHandler(type, cartInfo, disNum) {
        switch(type) {
          case 'add':
            disNum = 1;
            break;
          case 'minus':
            disNum = cartInfo.skuNum > 0 ? -1 : 0
            break;
          default:
            disNum = isNaN(disNum) ? 0 : disNum - cartInfo.skuNum
            break;
        }
        console.log(disNum)
        await reqAddOrUpdateShopCar(cartInfo.skuId, disNum)
        // console.log(result.data)
        this.getData()
      }
    }

4.6 删除购物车商品

没啥特别的,直接上代码了

\api\index.js

// /api/cart/deleteCart/{skuId}
export const reqDeleteCarList = (skuId) => {
    return requests({
        url: `/cart/deleteCart/${skuId}`,
        method: 'delete'
    })
}

\store\shopCar\index.js

async deleteCarInfo(context, skuId) {
        let result = await reqDeleteCarList(skuId)
        if(result.code === 200) {
            return 'ok'
        } else {
            return Promise.reject(new Error('failed'))
        }
    }

\pages\ShopCar\index.vue

async deleteCarInfo(skuId) {
      try {
        await this.$store.dispatch('deleteCarInfo', skuId)
        this.getData()
      }catch (err) {
        alert(err.message)
      }
    }

4.7 购物车商品修改的节流

可以发现在快速修改商品数量的时候会变成负数,因此需要对函数做节流,具体参照之前的随笔:【Vue项目】商品汇前台(二)进度条插件+Vuex模块化仓库+函数的防抖与节流+路由传参 - Tod4 - 博客园

    skuNumHandler: throttle(async function (type, cartInfo, disNum) {
      switch (type) {
        case 'add':
          disNum = 1;
          break;
        case 'minus':
          disNum = cartInfo.skuNum > 1 ? -1 : 0
          break;
        default:
          disNum = (isNaN(disNum) || disNum < 1) ? 1 : parseInt(disNum) - cartInfo.skuNum
          break;
      }
      await reqAddOrUpdateShopCar(cartInfo.skuId, disNum)
      // console.log(result.data)
      this.getData()
    }, 500),

4.8 修改产品是否选中的状态

也没啥特别的

\api\idnex.js

// /api/cart/checkCart/{skuID}/{isChecked}
export const reqCheckCart = (skuID, isChecked) => {
    return requests({
        url: `/cart/checkCart/${skuID}/${isChecked}`,
        method: 'get'
    })
}

vuex \store\shopCar\index.js

    async checkCart(context, {skuId, isChecked}) {
        let result = await reqCheckCart(skuId, isChecked)
        if(result.code === 200) {
            return 'ok'
        } else {
            return Promise.reject(new Error('failed'))
        }
    }

\pages\shopCar\index.vue

    async changeIsChecked(skuId) {
      let isChecked = event.target.checked ? 1 : 0
      try {
        await this.$store.dispatch('checkCart', {
          skuId: skuId,
          isChecked: isChecked
        })
        this.getData()
      }catch (err) {
        alert(err.message)
      }
    }

4.9 ☆ 删除所选的商品

分析:接口中没有删除多个商品的,因此需要多次调用之前的按照商品ID单独删除商品的接口,可以在仓库中创建一个action使用上下文context多次调用之前的单独删除的actiondeleteCarInfo,而调用action会返回promise,因此需要对多个promise执行一次Promise.all()才能得到五次的结果。

Promise.all()中的一个promise执行失败,则全部的promise都会失败

  • 编写仓库删除多个商品的action

\store\shopCar\index.js

    deleteAllCheckedCar({dispatch, getters}) {
        let promises = []
        getters.cartInfoList.cartInfoList.forEach(item => {
            if(item.isChecked === 1) {
                let promise = dispatch('deleteCarInfo', item.skuId)
                promises.push(promise)
            }
        })
        return Promise.all(promises)
    },
  • 编写组件的派发action的方法

\pages\ShopCar\index.vue

    async deleteAllCheckedCar() {
      try {
        await this.$store.dispatch('deleteAllCheckedCar')
        this.getData()
      }catch (err) {
        alert(err.message)
      }
    },

4.10 修改多个商品的选中状态

与上面差不多,直接贴代码了

\pages\ShopCar\index.vue

    changeAllCheckedCar({dispatch, getters}, isChecked) {
        let promises = []
        getters.cartInfoList.cartInfoList.forEach(item => {
            let promise = dispatch('checkCart', {
                skuId: item.skuId,
                isChecked: isChecked
            })
            promises.push(promise)
        })
        return Promise.all(promises)
    }

\store\shopCar\index.js

    async changeAllCheckedCar() {
      try{
        let isChecked = event.target.checked ?  1 : 0
        await this.$store.dispatch('changeAllCheckedCar', isChecked)
        this.getData()
      }catch (err) {
        alert(err.message)
      }
    }

标签:skuId,Vue,uuid,skuNum,尚品,购物车,disNum,store
来源: https://www.cnblogs.com/tod4/p/16653198.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有