搜索

查看: 3059|回复: 11

[ASP.NET] ASP.NET MVC实现横向展示购物车

[复制链接]
发表于 2023-5-4 11:34:14 | 显示全部楼层 |阅读模式
Editor 2023-5-4 11:34:14 3059 11 看全部
通常,我们看到的购物车是这样的:

2022911142314131.png

2022911142314131.png


虽然这种购物车显示方式被广泛运用,但我个人觉得不够直观。如果换成这样呢?

2022911142314132.png

2022911142314132.png


本篇的源码放在了:https://github.com/darrenji/ShoppingCartInMVC
以上购物车页能实现的效果包括:
1、购物车明细:显示订购数量、总金额,清空购物车。
2、购物车内产品:数量可调整,对应的小计和总计动态变化。点击移除按钮移除该产品。
3、继续购物按钮:点击左下角的继续购物按钮,回到先前页。
4、使用了Bootstrap, 页面元素自适应,页面宽度调小时,页面布局动态变化。
5、每行放置4个产品,且允许高度不一致,第5个产品另起一行,且不会float到上一行的空白区域,如下图。

2022911142314133.png

2022911142314133.png


首先,有关产品的类。
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string ImageUrl { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
    }
产品选购页如图:

2022911142314134.png

2022911142314134.png


以上,产品选购页是一个有关Product集合的强类型视图页,其对应的Model为:
    public class ProductsListVm
    {
        public ProductsListVm()
        {
            this.Products = new List();
        }
        public IEnumerable Products { get; set; }
    }
想像一下,我们在超市购物,在购物车内放着不同的商品对应不同的数量,在这里,可以把商品和数量抽象成一个类:
    public class CartLine
    {
        public Product Product { get; set; }
        public int Quantity { get; set; }
    }
而购物车类实际上就是维护着这个CartLine集合,需要提供添加、移除、计算购物车总价、清空购物车等方法,并提供一个获取到CartLine集合的属性,另外,针对点击购物车页上的增量和减量按钮,也要提供相应的方法。
    public class Cart
    {
        private List lineCollection = new List();
        //添加
        public void AddItem(Product product, int quantity)
        {
            CartLine line = lineCollection.Where(p => p.Product.Id == product.Id).FirstOrDefault();
            if (line == null)
            {
                lineCollection.Add(new CartLine(){Product = product, Quantity = quantity});
            }
            else
            {
                line.Quantity += quantity;
            }
        }
        //点击数量+号或点击数量-号或自己输入一个值
        public void IncreaseOrDecreaseOne(Product product, int quantity)
        {
            CartLine line = lineCollection.Where(p => p.Product.Id == product.Id).FirstOrDefault();
            if (line != null)
            {
                line.Quantity = quantity;
            }
        }
        //移除
        public void RemoveLine(Product product)
        {
            lineCollection.RemoveAll(p => p.Product.Id == product.Id);
        }
        //计算总价
        public decimal ComputeTotalPrice()
        {
            return lineCollection.Sum(p => p.Product.Price*p.Quantity);
        }
        //清空
        public void Clear()
        {
            lineCollection.Clear();
        }
        //获取
        public IEnumerable Lines
        {
            get { return lineCollection; }
        }
    }
购物车页自然就是针对Cart类的一个强类型视图页,嗯,等等,购物车页还需要记录下上一个页面的url,于是,考虑到把Cart类和记录上一个页面url这2个因素,针对购物车页,给出这样的一个Model:
    public class CartIndexVm
    {
        public Cart Cart { get; set; }
        public string ReturnUrl { get; set; }
    }
在HomeController中,需要用到购物车的实例,可以这样写:
private Cart GetCart()
{
    Cart cart = (Cart)Session["Cart"];
    if (cart == null)
    {
        cart = new Cart();
        Session["Cart"] = cart;
    }
    return cart;
}
Cart实例保存到Session中,并从Session中获取。当然,也可以放到ASP.NET MVC绑定机制中,需要做的就是实现IModelBinder接口。
    public class CartModelBinder : IModelBinder
    {
        private const string sessionKey = "Cart";
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            Cart cart = (Cart)controllerContext.HttpContext.Session[sessionKey];
            if (cart == null)
            {
                cart = new Cart();
                controllerContext.HttpContext.Session[sessionKey] = cart;
            }
            return cart;
        }
    }
自定义的ModelBinder需要在全局中注册。
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            ......
            ModelBinders.Binders.Add(typeof(Cart), new CartModelBinder());
        }
    }
在Home控制器中,首先提供了一个返回Product集合的方法。
        private List GetAllProducts()
        {
            return new List()
            {
                new Product(){Id = 1, Description = "产品描述产品描述产品描述产品描述产品描述产品描述产品描述",ImageUrl = "/images/1.jpg",Name = "产品1",Price = 85M},
                new Product(){Id = 2, Description = "产品描述产品描述产品描述产品描述产品描述产品描述产品描述",ImageUrl = "/images/2.jpg",Name = "产品2",Price = 95M},
                new Product(){Id = 3, Description = "产品描述产品描述产品描述",ImageUrl = "/images/2.jpg",Name = "产品3",Price = 55M},
                new Product(){Id = 4, Description = "产品描述产品描述产品描述产品描述产品描述产品描述产品描述",ImageUrl = "/images/1.jpg",Name = "产品4",Price = 65M},
                new Product(){Id = 5, Description = "产品描述产品描述产品描述产品描述产品描述产品描述产品描述",ImageUrl = "/images/2.jpg",Name = "产品5",Price = 75M}
            };
        }
在HomeController中,有关产品选购页的如下:
        //产品选购页
        public ActionResult Index()
        {
            ProductsListVm productsListVm = new ProductsListVm();
            productsListVm.Products = GetAllProducts();
            return View(productsListVm);
        }
Homme/Index.cshtml是一个ProductsListVm的强类型视图页。
@model MvcApplication1.Models.ProductsListVm
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
    .item {
        border-bottom: solid 1px gray;
    }

   
        @foreach (var item in Model.Products)
        {
            Html.RenderPartial("ProductSummary", item);
        }
   
其中,遍历Product集合的时候,又去加载Views/Shared/ProductSummary.cshtml这个强类型部分视图。
@model MvcApplication1.Models.Product
    @Model.Name
   


    @Model.Description
    @Model.Price.ToString("c")
    @using (Html.BeginForm("AddToCart", "Home"))
    {
        @Html.HiddenFor(p => p.Id)
        @Html.Hidden("returnUrl", Request.Url.PathAndQuery)
        
    }
点击"+放入购物车"按钮,调用HomeController中的AddToCart方法,并且需要把选购产品页的url以query string的形式传递给控制器方法。
        //购物车页
        public ActionResult CartIndex(Cart cart, string returnUrl)
        {
            return View(new CartIndexVm
            {
                Cart = cart,
                ReturnUrl = returnUrl
            });
        }
        //添加到购物车
        public ActionResult AddToCart(Cart cart, int id, string returnUrl)
        {
            Product product = GetAllProducts().Where(p => p.Id == id).FirstOrDefault();
            if (product != null)
            {
                cart.AddItem(product, 1);
            }
            return RedirectToAction("CartIndex", new {returnUrl});
        }
购物车页Home/CartIndex.cshtml是一个CartIndexVm的强类型视图页。
@model MvcApplication1.Models.CartIndexVm
@{
    ViewBag.Title = "CartIndex";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@section styles
{
   
   
}
   
      @for (int i = 0; i
          }
         
         
                 
               

               
                    @item.Product.Name
                    @item.Product.Description
                    
                        
单价:@item.Product.Price
数量:
                                    
                                
小计:@((item.Quantity * item.Product.Price).ToString("c"))

                    
               
               
                    
                        @using (Html.BeginForm("RemoveFromCart", "Home"))
                        {
                            @Html.Hidden("Id", item.Product.Id)
                            @Html.HiddenFor(x => x.ReturnUrl)
                           
                            查看
                        }
                        
                    
               
            
      }
              
   

   
        
           总计: @Model.Cart.ComputeTotalPrice().ToString("c")
        
        
            继续购物
        
   
@section scripts
{
   
   
}
在购物车页,用了Bootstrap TouchSpin这款插件,点击其中的数量的增量和减量按钮,就向Home控制器中的IncreaseOrDecreaseOne方法发送一个异步post请求,得到返回数据刷新购物车页。
       //点击数量+号或点击数量-号或自己输入一个值
        [HttpPost]
        public ActionResult IncreaseOrDecreaseOne(Cart cart, int id, int quantity)
        {
            Product product = GetAllProducts().Where(p => p.Id == id).FirstOrDefault();
            if (product != null)
            {
                cart.IncreaseOrDecreaseOne(product, quantity);
            }
            return Json(new
            {
                msg = true
            });
        }
在购车页,点击"移除"按钮,就向Home控制器的RemoveFromCart方法提交表单。
        //从购物车移除
        public ActionResult RemoveFromCart(Cart cart, int id, string returnUrl)
        {
            Product product = GetAllProducts().Where(p => p.Id == id).FirstOrDefault();
            if (product != null)
            {
                cart.RemoveLine(product);
            }
            return RedirectToAction("CartIndex", new {returnUrl});
        }
购物车摘要是通过在Views/Shared/_Layout.cshtml中加载部分视图而来。

   
   
    @ViewBag.Title
    @Styles.Render("~/Content/css")
   
    @RenderSection("styles", required: false)
    @Scripts.Render("~/bundles/jquery")
   

    @{Html.RenderAction("Summary", "Home");}
    @RenderBody()
    @RenderSection("scripts", required: false)

在Home控制器中,对应的Summary方法为:
        //清空购物车
        public ActionResult EmptyCart(Cart cart, string returnUrl)
        {
            cart.Clear();
            return View("Index",new ProductsListVm{Products = GetAllProducts()});
        }
        //显示购物车摘要
        public ActionResult Summary(Cart cart)
        {
            return View(cart);
        }
Home/Summary.cshtml是一个有关Cart的强类型部分视图:
@model MvcApplication1.Models.Cart
@{
    Layout = null;
}
   
        购物车明细:
        @if (Model != null)
        {
            @Model.Lines.Sum(x => x.Quantity) 件,
            @Model.ComputeTotalPrice().ToString("c")
        }
        
   
   
    @Html.ActionLink("结算", "CartIndex", "Home", new {returnUrl = Request.Url.PathAndQuery}, null)
     
    @Html.ActionLink("清空", "EmptyCart", "Home", new {returnUrl = Request.Url.PathAndQuery}, null)
注意:需要把Layout设置为null,否则会报错,因为产品选购页和购物车摘要同时加载Views/Shared/_Layout.cshtml就反复调用了。
到此这篇关于ASP.NET MVC实现横向展示购物车的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持知鸟论坛
回复

使用道具 举报

发表于 2023-6-28 21:36:05 | 显示全部楼层
哈哈SE7 2023-6-28 21:36:05 看全部
楼主,我太崇拜你了!我想我是一天也不能离开知鸟论坛
回复

使用道具 举报

发表于 2023-6-28 22:46:34 | 显示全部楼层
当当当当裤裆坦 2023-6-28 22:46:34 看全部
楼主发贴辛苦了,谢谢楼主分享!我觉得知鸟论坛是注册对了!
回复

使用道具 举报

发表于 2023-6-29 17:26:10 | 显示全部楼层
462710480 2023-6-29 17:26:10 看全部
其实我一直觉得楼主的品味不错!呵呵!知鸟论坛太棒了!
回复

使用道具 举报

发表于 2023-6-29 17:56:07 | 显示全部楼层
计划你大爷计j 2023-6-29 17:56:07 看全部
楼主,大恩不言谢了!知鸟论坛是最棒的!
回复

使用道具 举报

发表于 2023-6-29 18:27:06 | 显示全部楼层
普通人物怨 2023-6-29 18:27:06 看全部
感谢楼主的无私分享!要想知鸟论坛好 就靠你我他
回复

使用道具 举报

发表于 2023-6-30 08:36:27 | 显示全部楼层
我的苦恼冉 2023-6-30 08:36:27 看全部
我看不错噢 谢谢楼主!知鸟论坛越来越好!
回复

使用道具 举报

发表于 2023-6-30 13:24:18 | 显示全部楼层
向往草原403 2023-6-30 13:24:18 看全部
楼主,我太崇拜你了!我想我是一天也不能离开知鸟论坛
回复

使用道具 举报

发表于 2023-6-30 15:11:55 | 显示全部楼层
123456868 2023-6-30 15:11:55 看全部
这东西我收了!谢谢楼主!知鸟论坛真好!
回复

使用道具 举报

发表于 2023-6-30 22:07:51 | 显示全部楼层
塞翁364 2023-6-30 22:07:51 看全部
这个帖子不回对不起自己!我想我是一天也不能离开知鸟论坛
回复

使用道具 举报

  • 您可能感兴趣
点击右侧快捷回复 【请勿灌水】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则 返回列表

RSS订阅| SiteMap| 小黑屋| 知鸟论坛
联系邮箱E-mail:zniao@foxmail.com
快速回复 返回顶部 返回列表