购物车数据需全局使用,使用vuex管理全局数据

购物车数据结构设计

存储的购物车数据形式应该如下

  • 第一层是店铺的ID
  • 第二层是 shopName 和 products

    1. state: {
    2. cartList: {
    3. // shopId
    4. 1: {
    5. shopName: '沃尔玛',
    6. products: {
    7. // productId
    8. 1: {
    9. _id: 1,
    10. name: '番茄250g/份',
    11. imgUrl: 'https://img1.baidu.com/it/u=544840061,2614948313&fm=26&fmt=auto',
    12. sales: 10,
    13. price: 33.6,
    14. oldPrice: 39.6,
    15. count: 0,
    16. }
    17. },
    18. 2: {
    19. // productId
    20. 1: {
    21. // ...
    22. }
    23. }
    24. }
    25. }
    26. },

    加入购物车

    在mutation中写加入购物车方法

    1. changeCartItemInfo(state, payload) {
    2. const { shopId, productId, productInfo, num, shopName } = payload
    3. const shopInfo = state.cartList[shopId] || {}
    4. const products = shopInfo.products || {}
    5. let product = products[productId]
    6. if (!product) {
    7. product = productInfo
    8. product.count = 0
    9. }
    10. product.count += num
    11. products[productId] = product
    12. if (product.count > 0) {
    13. product.checked = true
    14. } else {
    15. delete products[productId]
    16. }
    17. shopInfo.products = products
    18. shopInfo.shopName = shopName
    19. state.cartList[shopId] = shopInfo
    20. saveCartListToLocalStorage(state)
    21. },

    在Content组件中创建useCartEffect ```tsx

const useCartEffect = () => { const store = useStore() const {cartList} = toRefs(store.state) const handleChangeCartItemInfo = (shopId, productId, productInfo, num, shopName) => { store.commit(‘changeCartItemInfo’, { shopId, productId, productInfo, num, shopName }) }

  1. return {
  2. cartList,
  3. handleChangeCartItemInfo
  4. }

}

  1. 显示 count
  2. ```vue
  3. <span>{{cartList?.[shopId]?.products[item._id]?.count || 0}}</span>

使用computed计算数量和价格

  1. const useCartEffect = () => {
  2. const route = useRoute()
  3. const shopId = route.params.id
  4. const store = useStore()
  5. const count = computed(() => {
  6. let total = 0
  7. // computed的依赖项,必须放里面
  8. const productList = cartList[`${shopId}`]?.products
  9. if (productList) {
  10. for (const i in productList) {
  11. total += productList[i].count
  12. }
  13. }
  14. return total
  15. })
  16. const total = computed(() => {
  17. let total = 0
  18. const productList = cartList[`${shopId}`]?.products
  19. if (productList) {
  20. for (const i in productList) {
  21. if (productList[i].checked) {
  22. total += productList[i].count * productList[i].price
  23. }
  24. }
  25. }
  26. return total.toFixed(2)
  27. })
  28. return {
  29. count, total
  30. }
  31. }

将购物车数据存储到localStorage

  1. import { createStore } from 'vuex'
  2. const saveCartListToLocalStorage = (state) => {
  3. const { cartList } = state
  4. localStorage.setItem('cartList', JSON.stringify(cartList))
  5. }
  6. const getCartListFromLocalStorage = () => {
  7. return JSON.parse(localStorage.getItem('cartList') || '{}')
  8. }
  9. export default createStore({
  10. state: {
  11. cartList: getCartListFromLocalStorage(), // 获取数据
  12. },
  13. mutations: {
  14. changeCartItemInfo(state, payload) {
  15. // ...
  16. saveCartListToLocalStorage(state) // 每次操作后存储数据
  17. },
  18. // ...
  19. }
  20. }

sticky 粘性定位

image.png
购物车内容滚动时,要使顶部固定,使用 position: sticky粘性定位,sticky 相对最近的滚动祖先定位

小技巧

只在底部显示内阴影
注意内阴影会被子元素的background覆盖

  1. box-shadow: inset 0 -1px 1px -1px rgba(0, 0, 0, .5);
  2. background: white;