老师 购物车想要通过后端接口进行创建和展示,需要在哪些地方进行修改,可以详细讲解一下吗(因为通过vuex好像有问题,即使登录不同的用户,购物车数据是被同步的)

老师 购物车想要通过后端接口进行创建和展示,需要在哪些地方进行修改,可以详细讲解一下吗(因为通过vuex好像有问题,即使登录不同的用户,购物车数据是被同步的)

Cart.vue页面

<template>

  <div

    class="mask"

    v-if="showCart && calculations.total > 0"

    @click="handleCartShowChange"

  />

  <div class="cart">

    <div class="product" v-if="showCart && calculations.total > 0">

      <div class="product__header">

        <div

          class="product__header__all"

          @click="() => setCartItemsChecked(shopId)"

        >

          <span

            class="product__header__icon iconfont"

            v-html="calculations.allChecked ? '&#xe652;': '&#xe603;'"

          >

          </span>

          全选

        </div>

        <div class="product__header__clear">

          <span class="product__header__clear__btn"

            @click="() => cleanCartProducts(shopId)"

          >清空购物车</span>

        </div>

      </div>

      <div

        v-for="item in productList"

        :key="item.id"

        class="product__item"

      >

        <div

          class="product__item__checked iconfont"

          v-html="item.check ? '&#xe652;': '&#xe603;'"

          @click="() => changeCartItemChecked(shopId, item.id)"

        />

        <img class="product__item__img" :src="item.imgUrl" />

        <div class="product__item__detail">

          <h4 class="product__item__title">{{item.name}}</h4>

          <p class="product__item__price">

            <span class="product__item__yen">&yen;</span>{{item.price}}

            <span class="product__item__origin">&yen;{{item.oldPrice}}</span>

          </p>

        </div>

        <div class="product__number">

          <span

            class="product__number__minus iconfont"

            @click="() => { changeCartItemInfo(shopId, item.id, item, -1) }"

          >&#xe677;</span>

          <span class="product__number__value">{{item.count || 0}}</span>

          <span

            class="product__number__plus iconfont"

            @click="() => { changeCartItemInfo(shopId, item.id, item, 1) }"

          >&#xe845;</span>

        </div>

      </div>

    </div>

    <div class="check">

      <div class="check__icon">

        <img

          src="http://www.dell-lee.com/imgs/vue3/basket.png"

          class="check__icon__img"

          @click="handleCartShowChange"

        />

        <div class="check__icon__tag">{{calculations.total}}</div>

      </div>

      <div class="check__info">

        总计:<span class="check__info__price">&yen; {{calculations.price}}</span>

      </div>

      <div class="check__btn" v-show="calculations.total > 0">

        <!-- 跳转到提交订单页面 -->

        <router-link :to="{path: `/orderConfirmation/${shopId}`}">

          去结算

        </router-link>

      </div>

    </div>

  </div>

</template>


<script>

import { ref } from 'vue'

import { useStore } from 'vuex'

import { useRoute } from 'vue-router'

import { useCommonCartEffect } from '../../effects/cartEffects'


// 获取购物车信息逻辑

const useCartEffect = (shopId) => {

  const store = useStore()

  const {

    productList, calculations, changeCartItemInfo

  } = useCommonCartEffect(shopId)


  const changeCartItemChecked = (shopId, productId) => {

    store.commit('changeCartItemChecked', { shopId, productId })

  }


  const cleanCartProducts = (shopId) => {

    store.commit('cleanCartProducts', { shopId })

  }


  const setCartItemsChecked = (shopId) => {

    // 如果全选状态,点击按钮后取消全选,如果非全选状态,点击按钮后全部选中

    const allChecked = !calculations.value.allChecked

    store.commit('setCartItemsChecked', { shopId, allChecked })

  }


  return {

    calculations, productList, cleanCartProducts, changeCartItemInfo, changeCartItemChecked, setCartItemsChecked

  }

}


// 展示隐藏购物车逻辑

const toggleCartEffect = () => {

  const showCart = ref(false)

  const handleCartShowChange = () => {

    showCart.value = !showCart.value

  }

  return { showCart, handleCartShowChange }

}


export default {

  name: 'Cart',

  setup () {

    const route = useRoute()

    const shopId = route.params.id

    const {

      calculations, productList, cleanCartProducts,

      changeCartItemInfo, changeCartItemChecked, setCartItemsChecked

    } = useCartEffect(shopId)

    const { showCart, handleCartShowChange } = toggleCartEffect()

    return {

      calculations, shopId, productList, cleanCartProducts, changeCartItemInfo, changeCartItemChecked, setCartItemsChecked, showCart, handleCartShowChange

    }

  }

}

</script>


<style lang="scss" scoped>

@import '../../style/viriables.scss';

@import '../../style/mixins.scss';

.mask {

  position: fixed;

  left: 0;

  right: 0;

  bottom: 0;

  top: 0;

  background: rgba(0, 0, 0, .5);

  z-index: 1;

}

.cart {

  position: absolute;

  left: 0;

  right: 0;

  bottom: 0;

  z-index: 2;

  background: $bgColor;

}

.product {

  overflow-y: scroll;

  flex: 1;

  background: $bgColor;

  &__header {

    display: flex;

    line-height: .52rem;

    border-bottom: .01rem solid $content-bgColor;

    font-size: .14rem;

    color: $content-fontcolor;

    &__all {

      width: .64rem;

      margin-left: .18rem;

    }

    &__icon {

      display: inline-block;

      margin-right: .1rem;

      vertical-align: top;

      color: $btn-bgColor;

      font-size: .2rem;

    }

    &__clear {

      flex: 1;

      margin-right: .16rem;

      text-align: right;

      &__btn {

        display: inline-block;

      }

    }

  }

  &__item {

    position: relative;

    display: flex;

    padding: .12rem 0;

    margin: 0 .18rem;

    border-bottom: .01rem solid $content-bgColor;

    &__checked {

      line-height: .5rem;

      margin-right: .2rem;

      color: $btn-bgColor;

      font-size: .2rem;

    }

    &__detail {

      overflow: hidden;

    }

    &__img {

      width: .46rem;

      height: .46rem;

      margin-right: .16rem;

    }

    &__title {

      margin: 0;

      line-height: .2rem;

      font-size: .14rem;

      color: $content-fontcolor;

      @include ellipsis;

    }

    &__price {

      margin: .06rem 0 0 0;

      line-height: .2rem;

      font-size: .14rem;

      color: $hightlight-fontColor;

    }

    &__yen {

      font-size: .12rem;

    }

    &__origin {

      margin-left: .06rem;

      line-height: .2rem;

      font-size: .12rem;

      color: $light-fontColor;

      text-decoration: line-through;

    }

    .product__number {

      position: absolute;

      right: 0;

      bottom: .26rem;

      &__minus {

        position:relative;

        top: .02rem;

        color: $medium-fontColor;

        margin-right: .05rem;

        font-size: .2rem;

      }

      &__plus {

        position:relative;

        top: .02rem;

        color: $btn-bgColor;

        margin-left: .05rem;

        font-size: .2rem;

      }

      &__value {

        font-size: .13rem;

      }

    }

  }

}

.check {

  display: flex;

  height: .49rem;

  border-top: .01rem solid $content-bgColor;

  line-height: .49rem;

  &__icon {

    position: relative;

    width: .84rem;

    &__img {

      display: block;

      margin: .12rem auto;

      width: .28rem;

      height: .26rem;

    }

    &__tag {

      position: absolute;

      left: .46rem;

      top: .04rem;

      padding: 0 .04rem;

      min-width: .2rem;

      height: .2rem;

      line-height: .2rem;

      background-color: $hightlight-fontColor;

      border-radius: .1rem;

      font-size: .12rem;

      text-align: center;

      color: $bgColor;

      transform: scale(.5);

      transform-origin: left center;

    }

  }

  &__info {

    flex: 1;

    color: $content-fontcolor;

    font-size: .12rem;

    &__price {

      line-height: .49rem;

      color: $hightlight-fontColor;

      font-size: .18rem;

    }

  }

  &__btn {

    width: .98rem;

    background-color: #4FB0F9;

    text-align: center;

    font-size: .14rem;

    a {

      color: $bgColor;

      text-decoration: none;

    }

  }

}

</style>

=================================

cartEffects.js页面

import { computed } from 'vue'

import { useStore } from 'vuex'

// 购物车相关逻辑

export const useCommonCartEffect = (shopId) => {

  const store = useStore()

  const cartList = store.state.cartList

  const changeCartItemInfo = (shopId, productId, productInfo, num) => {

    store.commit('changeCartItemInfo', {

      shopId, productId, productInfo, num

    })

  }


  const productList = computed(() => {

    const productList = cartList[shopId]?.productList || {}

    const notEmptyProductList = {}

    for (const i in productList) {

      const product = productList[i]

      if (product.count > 0) {

        notEmptyProductList[i] = product

      }

    }

    return notEmptyProductList

  })


  const shopName = computed(() => {

    const shopName = cartList[shopId]?.shopName || ''

    return shopName

  })


  const calculations = computed(() => {

    const productList = cartList[shopId]?.productList

    const result = { total: 0, price: 0, allChecked: true }

    if (productList) {

      for (const i in productList) {

        const product = productList[i]

        result.total += product.count

        if (product.check) {

          result.price += (product.count * product.price)

        }

        if (product.count > 0 && !product.check) {

          result.allChecked = false

        }

      }

    }

    result.price = result.price.toFixed(2)

    return result

  })

  return { cartList, shopName, productList, calculations, changeCartItemInfo }

}

==================================

store文件夹的index.js页面

import Vuex from 'vuex'

import { post } from '../utils/request'


// 给cartList数据做持久存储

const setLocalCartList = (state) => {

  const { cartList } = state

  const cartListString = JSON.stringify(cartList)

  localStorage.cartList = cartListString

}


const getLocalCartList = () => {

  // { shopId: {shopName:'', productList:{ productId: {} }}}

  try {

    return JSON.parse(localStorage.cartList)

  } catch (e) {

    return {

      cartList: {}

    }

  }

}


export default Vuex.createStore({

  state: {

    cartList: getLocalCartList(),

    userId: ''

  },

  mutations: {

    saveUserId (state, payload) {

      state.userId = payload.userId

    },

    changeCartItemInfo (state, payload) {

      const { shopId, productId, productInfo } = payload

      const shopInfo = state.cartList[shopId] || {

        shopName: '', productList: {}

      }

      let product = shopInfo.productList[productId]

      if (!product) {

        productInfo.count = 0

        product = productInfo

      }

      product.count = product.count + payload.num

      if (payload.num > 0) { product.check = true }

      if (product.count < 0) { product.count = 0 }

      shopInfo.productList[productId] = product

      state.cartList[shopId] = shopInfo

      console.log('cart state:', state)

      console.log('userId:', state.userId, 'shopId:', shopId, 'goodsId:', product.id, 'goodsNum:', product.count, 'goodsName:', product.goodsName, 'img:', product.imgUrl)

      // 加入购物车

      const addCart = async () => {

        try {

          const result = await post('/cart/create', {

            shopId: shopId,

            goodsId: product.id,

            goodsNum: product.count,

            goodsName: product.goodsName,

            img: product.imgUrl

          })

          if (result?.code === 1) {

            console.log('添加购物车成功')

          } else {

            console.log('添加购物车失败')

          }

        } catch (e) {

          console.log('请求失败')

        }

      }

      addCart()

      setLocalCartList(state)

    },

    changeShopName (state, payload) {

      const { shopId, shopName } = payload

      const shopInfo = state.cartList[shopId] || {

        shopName: '', productList: {}

      }

      shopInfo.shopName = shopName

      state.cartList[shopId] = shopInfo

      setLocalCartList(state)

    },

    changeCartItemChecked (state, payload) {

      const { shopId, productId } = payload

      const product = state.cartList[shopId].productList[productId]

      product.check = !product.check

      setLocalCartList(state)

    },

    cleanCartProducts (state, payload) {

      const { shopId } = payload

      state.cartList[shopId].productList = {}

      setLocalCartList(state)

    },

    setCartItemsChecked (state, payload) {

      // 接收allChecked

      const { shopId, allChecked } = payload

      const products = state.cartList[shopId].productList

      if (products) {

        for (const key in products) {

          const product = products[key]

          // 如果allChecked值为true,将每个商品的check值设为true

          if (allChecked) {

            product.check = true

          } else {

            // 如果allChecked值为false,将每个商品的check值设为false

            product.check = false

          }

        }

      }

      setLocalCartList(state)

    },

    clearCartData (state, shopId) {

      state.cartList[shopId].productList = {}

    }

  }

})




正在回答 回答被采纳积分+1

登陆购买课程后可参与讨论,去登陆

1回答
好帮手慕小李 2022-04-14 12:03:34

同学你好,解答如下:

1、首先要说一点购物车不能直接使用后端接口进行创建和展示,正常开发中是不允许的,如果每点击增加一次都要去访问后端,那么当并发量大的时候服务器端就崩了,并且这还是访问量大的电商项目。

2、vuex不是有问题,而是项目是开发阶段,如按照正常项目来说,他们在请求的时候是要带用户的token的,这样服务端就会去区别是谁在访问了,之后后端会给到前端对应用户的数据。我们在学习的时候因为都是本地开发,并没有办法去真的区分是谁在访问,另vuex在正式开发中要优化,因为如果用户在页面中刷新,会导致vuex数据被清空,所以vuex一般来说会在某些特定的场所赋值给本地缓存进行保存数据,正是因为这样所以同学即便是在怎么换账号密码,本地依然会存在数据,所以才会导致被同步的现象发生。

祝学习愉快!

  • 提问者 lcy_18 #1

    那如果我现在想用接口来进行数据的存储和调用具体该在哪里处理呢,或者老师可以讲解一下token在视频中的源码中该如何添加上

    2022-04-14 12:50:36
  • 好帮手慕小李 回复 提问者 lcy_18 #2

    同学你好,解答如下:

    1、用接口进行渲染,那么就在需要展示的页面单独写请求即可,如同学不清楚可以去复习一下课程,这里在存放vuex的时候或者取vuex值的时候就可以替换成数据请求,老师这里没有实质的接口,没办法给同学做演示。另外同学可以自己在数据库中创建两条不同的数据,比如用户1对应的数据是什么,用户2对应的数据是什么。如下:

    {

        data:{

            user1:{

                

            },

            user2:{


            }

        }

    }

    按照类似以上的数据格式,然后相当于是请求user1与user2假装是在切换登录。

    2、我们的课程中不涉及token的相关知识点,https://class.imooc.com/lesson/1731#mid=42295 视频中已经有讲过,我们这里的登录是模拟的。同学要实现需要调用后端的接口。如上面讲到的,token发送给后端,后端会维护登录态,然后用来区分用户,然后同学再请求后端的时候返回的数据,后端会根据token来区分返回的数据给到谁。同学如果之前做过项目,应该会知道比如说某个接口需要传用户标识,比如说userId这样的字段。如果同学还在学习阶段,那么建议先把视频中讲到的知识点先弄清楚。

    祝学习愉快!

    2022-04-14 13:20:52
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师