📅 Day 4:购物车功能实现

✅ 今日目标:

  • 创建 CartItem 模型
  • 使用 Session 实现购物车数据存储(可选数据库)
  • 实现加入购物车、查看购物车、修改数量功能
  • 提交 Git 版本记录进度

🧩 功能概览

页面 功能
/Cart/Index.cshtml 查看当前购物车内容
/Cart/AddToCart.cshtml 添加商品到购物车
_Layout.cshtml 显示购物车商品数量
可选 清空购物车 / 删除单项

🛠️ 知识点预览

技术 内容
数据模型 CartItem 表示单个购物车条目
存储方式 使用 Session 暂存购物车(轻量级)
页面交互 商品详情页添加“加入购物车”按钮
UI 设计 使用 Bootstrap 展示购物车列表和总价
扩展建议 后续可改为使用数据库 + 用户 ID 关联

🧱 第一步:创建 CartItem 模型

Models 文件夹中创建 CartItem.cs

namespace ECommercePlatform.Models
{
    public class CartItem
    {
        public int ProductId { get; set; }
        public string Name { get; set; } = string.Empty;
        public decimal Price { get; set; }
        public int Quantity { get; set; }
        public string ImageUrl { get; set; } = string.Empty;

        // 总价计算
        public decimal TotalPrice => Price * Quantity;
    }
}

🧰 第二步:创建购物车服务(SessionCartService)

创建一个服务类来处理 Session 中的购物车数据。

✅ 创建 Services/IShoppingCartService.cs

using ECommercePlatform.Models;

public interface IShoppingCartService
{
    IList<CartItem> GetCartItems();
    void AddToCart(int productId, string productName, decimal productPrice, string imageUrl, int quantity = 1);
    void RemoveFromCart(int productId);
    void ClearCart();
    int GetCartItemCount();
    decimal GetTotalPrice();
}

✅ 创建 Services/SessionCartService.cs

using Microsoft.AspNetCore.Http;
using System.Text.Json;
using ECommercePlatform.Models;

public class SessionCartService : IShoppingCartService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public SessionCartService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    private const string CartSessionKey = "CartItems";

    private List<CartItem> GetCartItemsFromSession()
    {
        var session = _httpContextAccessor.HttpContext.Session;
        var data = session.GetString(CartSessionKey);
        if (string.IsNullOrEmpty(data))
        {
            return new List<CartItem>();
        }
        return JsonSerializer.Deserialize<List<CartItem>>(data) ?? new List<CartItem>();
    }

    private void SaveCartItemsToSession(List<CartItem> cartItems)
    {
        var session = _httpContextAccessor.HttpContext.Session;
        var options = new JsonSerializerOptions { WriteIndented = true };
        var data = JsonSerializer.Serialize(cartItems, options);
        session.SetString(CartSessionKey, data);
    }

    public IList<CartItem> GetCartItems()
    {
        return GetCartItemsFromSession();
    }

    public void AddToCart(int productId, string productName, decimal productPrice, string imageUrl, int quantity = 1)
    {
        var cartItems = GetCartItemsFromSession();

        var existingItem = cartItems.FirstOrDefault(c => c.ProductId == productId);
        if (existingItem != null)
        {
            existingItem.Quantity += quantity;
        }
        else
        {
            cartItems.Add(new CartItem
            {
                ProductId = productId,
                Name = productName,
                Price = productPrice,
                ImageUrl = imageUrl,
                Quantity = quantity
            });
        }

        SaveCartItemsToSession(cartItems);
    }

    public void RemoveFromCart(int productId)
    {
        var cartItems = GetCartItemsFromSession();
        var itemToRemove = cartItems.FirstOrDefault(c => c.ProductId == productId);
        if (itemToRemove != null)
        {
            cartItems.Remove(itemToRemove);
        }
        SaveCartItemsToSession(cartItems);
    }

    public void ClearCart()
    {
        var session = _httpContextAccessor.HttpContext.Session;
        session.Remove(CartSessionKey);
    }

    public int GetCartItemCount()
    {
        return GetCartItemsFromSession().Sum(c => c.Quantity);
    }

    public decimal GetTotalPrice()
    {
        return GetCartItemsFromSession().Sum(c => c.TotalPrice);
    }
}

🧪 第三步:注册服务(Program.cs)

builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddScoped<IShoppingCartService, SessionCartService>();

🛒 第四步:创建购物车页面(Pages/Cart/Index)

✅ Index.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;
using ECommercePlatform.Services;
using ECommercePlatform.Models;

namespace ECommercePlatform.Pages.Cart
{
    public class IndexModel : PageModel
    {
        private readonly IShoppingCartService _cartService;

        public IndexModel(IShoppingCartService cartService)
        {
            _cartService = cartService;
        }

        public IList<CartItem> CartItems { get; set; } = new List<CartItem>();
        public decimal TotalPrice { get; set; }

        public void OnGet()
        {
            CartItems = _cartService.GetCartItems();
            TotalPrice = _cartService.GetTotalPrice();
        }
    }
}

✅ Index.cshtml

@page
@model ECommercePlatform.Pages.Cart.IndexModel

<h2>我的购物车</h2>

@if (Model.CartItems.Count == 0)
{
    <p>购物车为空。</p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>商品图片</th>
                <th>名称</th>
                <th>单价</th>
                <th>数量</th>
                <th>总价</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.CartItems)
            {
                <tr>
                    <td><img src="@item.ImageUrl" width="50" /></td>
                    <td>@item.Name</td>
                    <td>$@item.Price</td>
                    <td>@item.Quantity</td>
                    <td>$@item.TotalPrice</td>
                    <td>
                        <form method="post" asp-page-handler="Remove" asp-route-id="@item.ProductId">
                            <button type="submit" class="btn btn-danger btn-sm">移除</button>
                        </form>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <h4>总计:$@Model.TotalPrice</h4>
}

🧩 第五步:在商品详情页添加“加入购物车”按钮

修改 Pages/Products/Details.cshtml

<form method="post" asp-page="/Cart/AddToCart">
    <input type="hidden" name="productId" value="@Model.Product.Id" />
    <input type="hidden" name="productName" value="@Model.Product.Name" />
    <input type="hidden" name="productPrice" value="@Model.Product.Price" />
    <input type="hidden" name="imageUrl" value="@Model.Product.ImageUrl" />

    <button type="submit" class="btn btn-warning">加入购物车</button>
</form>

✅ 创建 AddToCart.cshtml 和 AddToCart.cshtml.cs

AddToCart.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ECommercePlatform.Services;

namespace ECommercePlatform.Pages.Cart
{
    public class AddToCartModel : PageModel
    {
        private readonly IShoppingCartService _cartService;

        public AddToCartModel(IShoppingCartService cartService)
        {
            _cartService = cartService;
        }

        [BindProperty]
        public int productId { get; set; }
        [BindProperty]
        public string productName { get; set; } = string.Empty;
        [BindProperty]
        public decimal productPrice { get; set; }
        [BindProperty]
        public string imageUrl { get; set; } = string.Empty;

        public IActionResult OnPost()
        {
            _cartService.AddToCart(productId, productName, productPrice, imageUrl);
            return RedirectToPage("/Cart/Index");
        }
    }
}

🧾 第六步:在导航栏显示购物车数量(_Layout.cshtml)

<li class="nav-item">
    @{
        var cartService = HttpContext.RequestServices.GetService<IShoppingCartService>();
        var count = cartService?.GetCartItemCount() ?? 0;
    }
    <a class="nav-link" href="/Cart/Index">🛒 购物车 (@count)</a>
</li>

📦 第七步:提交 Git 版本

git add .
git commit -m "Day4: Added shopping cart functionality with session-based storage"

📝 今日总结

今天你完成了:

✅ 创建 CartItem 模型
✅ 使用 Session 实现购物车逻辑(轻量、快速开发)
✅ 实现加入购物车、查看购物车、删除商品功能
✅ 在商品详情页添加“加入购物车”按钮
✅ 在导航栏显示购物车数量
✅ 提交版本控制记录


📆 明日计划(Day5)

我们将进入 订单提交与支付模拟阶段

  • 创建 Order, OrderItem 模型
  • 从购物车生成订单
  • 模拟支付流程(成功/失败页面)
  • 订单状态跟踪(待付款、已发货等)
Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐