实现一个简单的购物车:Vue3 状态管理的实战

在前端开发中,购物车是许多应用中的一个关键部分。随着Vue3的推出,我们可以利用其新特性,特别是组合式 API(setup 语法糖),来实现一个简单而实用的购物车功能。在这篇文章中,我们将逐步构建一个基本的购物车应用,并深入了解Vue3的状态管理如何工作。

项目结构

首先,我们创建一个新的Vue 3项目并设置项目结构。可以使用Vue CLI创建项目:

vue create shopping-cart

选择默认配置后,项目结构大致如下:

shopping-cart/
|-- src/
|   |-- components/
|   |   |-- Cart.vue
|   |   |-- ProductList.vue
|   |-- App.vue
|   |-- main.js
|-- public/

src/components 目录下,我们将创建两个组件:Cart.vueProductList.vue

创建状态管理

为了管理购物车的状态,我们可以使用Vue 3提供的 reactiveref 来创建一个简单的状态管理。我们将创建一个 useCart 钩子,负责购物车的所有状态和逻辑。

src 目录下创建一个新文件 useCart.js

// src/useCart.js
import { reactive, computed } from 'vue';

const state = reactive({
    cart: []
});

const addToCart = (product) => {
    const existingProduct = state.cart.find(item => item.id === product.id);
    
    if (existingProduct) {
        existingProduct.quantity += 1;
    } else {
        state.cart.push({ ...product, quantity: 1 });
    }
};

const removeFromCart = (productId) => {
    state.cart = state.cart.filter(item => item.id !== productId);
};

const totalItems = computed(() => {
    return state.cart.reduce((total, item) => total + item.quantity, 0);
});

const totalPrice = computed(() => {
    return state.cart.reduce((total, item) => total + item.price * item.quantity, 0).toFixed(2);
});

export default function useCart() {
    return {
        state,
        addToCart,
        removeFromCart,
        totalItems,
        totalPrice,
    };
}

在这个 useCart.js 文件中,我们定义了一个 state 对象,其中包含购物车的商品。我们也定义了addToCartremoveFromCart 函数来添加和移除商品,以及计算总商品数量和总价格的计算属性。

创建产品列表组件

接下来,我们将创建一个 ProductList.vue 组件来展示可购买的商品,并实现添加到购物车的功能。

<!-- src/components/ProductList.vue -->
<template>
  <div>
    <h2>产品列表</h2>
    <div class="product" v-for="product in products" :key="product.id">
      <h3>{{ product.name }}</h3>
      <p>价格: ${{ product.price.toFixed(2) }}</p>
      <button @click="addToCart(product)">加入购物车</button>
    </div>
  </div>
</template>

<script>
import useCart from '../useCart';

export default {
  setup() {
    const { addToCart } = useCart();
    
    const products = [
      { id: 1, name: '商品1', price: 29.99 },
      { id: 2, name: '商品2', price: 39.99 },
      { id: 3, name: '商品3', price: 49.99 },
    ];

    return {
      products,
      addToCart,
    };
  }
}
</script>

<style scoped>
.product {
    border: 1px solid #ccc;
    padding: 10px;
    margin: 10px 0;
}
</style>

在这个组件中,我们定义了一个简单的产品列表,通过 v-for 指令循环遍历所有商品,并为每个商品添加了一个“加入购物车”按钮。点击按钮时,调用 addToCart 方法将商品添加到购物车。

创建购物车组件

接下来,我们将创建 Cart.vue 组件来展示购物车中的商品并实现移除功能。

<!-- src/components/Cart.vue -->
<template>
  <div>
    <h2>购物车</h2>
    <div v-if="cart.length === 0">购物车是空的</div>
    <div v-else>
      <ul>
        <li v-for="item in cart" :key="item.id">
          {{ item.name }} - {{ item.quantity }} x ${{ item.price.toFixed(2) }}
          <button @click="removeFromCart(item.id)">移除</button>
        </li>
      </ul>
      <p>总商品数: {{ totalItems }}</p>
      <p>总价格: ${{ totalPrice }}</p>
    </div>
  </div>
</template>

<script>
import useCart from '../useCart';

export default {
  setup() {
    const { state, removeFromCart, totalItems, totalPrice } = useCart();

    return {
      cart: state.cart,
      removeFromCart,
      totalItems,
      totalPrice,
    };
  }
}
</script>

<style scoped>
ul {
    list-style-type: none;
    padding: 0;
}
</style>

在这个组件中,我们从状态管理中获取购物车中的商品,并展示它们的名称、数量和价格。同时我们计算总商品数和总价格。如有需要,还可以通过“移除”按钮来移除购物车中的商品。

整合一切

最后,我们需要将这些组件整合到 App.vue 中:

<!-- src/App.vue -->
<template>
  <div id="app">
    <h1>简单购物车示例</h1>
    <ProductList />
    <Cart />
  </div>
</template>

<script>
import ProductList from './components/ProductList.vue';
import Cart from './components/Cart.vue';

export default {
  components: {
    ProductList,
    Cart,
  },
}
</script>

<style>
#app {
    max-width: 600px;
    margin: auto;
}
</style>

App.vue 中,我们引入并使用 ProductListCart 组件,使我们的购物车应用可以正常运行。

总结

至此,我们已经利用Vue 3中的组合式 API 创建了一个简单的购物车应用。通过使用 reactivecomputed 管理状态,我们能够高效并简洁地管理购物车的功能。

这个项目为你提供了一个基础,可以在此基础上扩展更多功能,例如用户认证、持久化购物车数据到本地存储等。


最后问候亲爱的朋友们,并诚挚地邀请你们阅读我的全新著作。书籍简介

实现一个简单的购物车:Vue3状态管理的实战_List