ASP.NET MVC實(shí)現(xiàn)橫向展示購物車
通常,我們看到的購物車是這樣的:
雖然這種購物車顯示方式被廣泛運(yùn)用,但我個(gè)人覺得不夠直觀。如果換成這樣呢?
本篇的源碼放在了:https://github.com/darrenji/ShoppingCartInMVC
以上購物車頁能實(shí)現(xiàn)的效果包括:
1、購物車明細(xì):顯示訂購數(shù)量、總金額,清空購物車。
2、購物車內(nèi)產(chǎn)品:數(shù)量可調(diào)整,對應(yīng)的小計(jì)和總計(jì)動(dòng)態(tài)變化。點(diǎn)擊移除按鈕移除該產(chǎn)品。
3、繼續(xù)購物按鈕:點(diǎn)擊左下角的繼續(xù)購物按鈕,回到先前頁。
4、使用了Bootstrap, 頁面元素自適應(yīng),頁面寬度調(diào)小時(shí),頁面布局動(dòng)態(tài)變化。
5、每行放置4個(gè)產(chǎn)品,且允許高度不一致,第5個(gè)產(chǎn)品另起一行,且不會(huì)float到上一行的空白區(qū)域,如下圖。
首先,有關(guān)產(chǎn)品的類。
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; } }
產(chǎn)品選購頁如圖:
以上,產(chǎn)品選購頁是一個(gè)有關(guān)Product集合的強(qiáng)類型視圖頁,其對應(yīng)的Model為:
public class ProductsListVm {public ProductsListVm(){ this.Products = new List<Product>();}public IEnumerable<Product> Products { get; set; } }
想像一下,我們在超市購物,在購物車內(nèi)放著不同的商品對應(yīng)不同的數(shù)量,在這里,可以把商品和數(shù)量抽象成一個(gè)類:
public class CartLine {public Product Product { get; set; }public int Quantity { get; set; } }
而購物車類實(shí)際上就是維護(hù)著這個(gè)CartLine集合,需要提供添加、移除、計(jì)算購物車總價(jià)、清空購物車等方法,并提供一個(gè)獲取到CartLine集合的屬性,另外,針對點(diǎn)擊購物車頁上的增量和減量按鈕,也要提供相應(yīng)的方法。
public class Cart {private List<CartLine> lineCollection = new List<CartLine>();//添加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; }}//點(diǎn)擊數(shù)量+號(hào)或點(diǎn)擊數(shù)量-號(hào)或自己輸入一個(gè)值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);}//計(jì)算總價(jià)public decimal ComputeTotalPrice(){ return lineCollection.Sum(p => p.Product.Price*p.Quantity);}//清空public void Clear(){ lineCollection.Clear();}//獲取public IEnumerable<CartLine> Lines{ get { return lineCollection; }} }
購物車頁自然就是針對Cart類的一個(gè)強(qiáng)類型視圖頁,嗯,等等,購物車頁還需要記錄下上一個(gè)頁面的url,于是,考慮到把Cart類和記錄上一個(gè)頁面url這2個(gè)因素,針對購物車頁,給出這樣的一個(gè)Model:
public class CartIndexVm {public Cart Cart { get; set; }public string ReturnUrl { get; set; } }
在HomeController中,需要用到購物車的實(shí)例,可以這樣寫:
private Cart GetCart(){ Cart cart = (Cart)Session["Cart"]; if (cart == null) {cart = new Cart();Session["Cart"] = cart; } return cart;}
Cart實(shí)例保存到Session中,并從Session中獲取。當(dāng)然,也可以放到ASP.NET MVC綁定機(jī)制中,需要做的就是實(shí)現(xiàn)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控制器中,首先提供了一個(gè)返回Product集合的方法。
private List<Product> GetAllProducts(){ return new List<Product>() {new Product(){Id = 1, Description = "產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述",ImageUrl = "/images/1.jpg",Name = "產(chǎn)品1",Price = 85M},new Product(){Id = 2, Description = "產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述",ImageUrl = "/images/2.jpg",Name = "產(chǎn)品2",Price = 95M},new Product(){Id = 3, Description = "產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述",ImageUrl = "/images/2.jpg",Name = "產(chǎn)品3",Price = 55M},new Product(){Id = 4, Description = "產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述",ImageUrl = "/images/1.jpg",Name = "產(chǎn)品4",Price = 65M},new Product(){Id = 5, Description = "產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述產(chǎn)品描述",ImageUrl = "/images/2.jpg",Name = "產(chǎn)品5",Price = 75M} };}
在HomeController中,有關(guān)產(chǎn)品選購頁的如下:
//產(chǎn)品選購頁public ActionResult Index(){ ProductsListVm productsListVm = new ProductsListVm(); productsListVm.Products = GetAllProducts(); return View(productsListVm);}
Homme/Index.cshtml是一個(gè)ProductsListVm的強(qiáng)類型視圖頁。
@model MvcApplication1.Models.ProductsListVm@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml";}<style type="text/css"> .item {border-bottom: solid 1px gray; }</style><div> <div>@foreach (var item in Model.Products){ Html.RenderPartial("ProductSummary", item);} </div></div>
其中,遍歷Product集合的時(shí)候,又去加載Views/Shared/ProductSummary.cshtml這個(gè)強(qiáng)類型部分視圖。
@model MvcApplication1.Models.Product<div> <h3>@Model.Name</h3> <p><img src="@Model.ImageUrl"/></p> <p>@Model.Description</p> <h4>@Model.Price.ToString("c")</h4> @using (Html.BeginForm("AddToCart", "Home")) {@Html.HiddenFor(p => p.Id)@Html.Hidden("returnUrl", Request.Url.PathAndQuery)<input type="submit" value="+放入購物車"/> }</div>
點(diǎn)擊"+放入購物車"按鈕,調(diào)用HomeController中的AddToCart方法,并且需要把選購產(chǎn)品頁的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是一個(gè)CartIndexVm的強(qiáng)類型視圖頁。
@model MvcApplication1.Models.CartIndexVm@{ ViewBag.Title = "CartIndex"; Layout = "~/Views/Shared/_Layout.cshtml";}@section styles{ <link href="~/Content/shopitem.css" rel="external nofollow" rel="stylesheet" /> <link href="~/Content/jquery.bootstrap-touchspin.min.css" rel="external nofollow" rel="stylesheet" />}<div> <div> @for (int i = 0; i < Model.Cart.Lines.Count(); i++) { var item = (Model.Cart.Lines.ToList())[i]; if (i != 0 && i%4 == 0) //每行有4個(gè)div { <div></div> } <div> <img src="@item.Product.ImageUrl"><div> <div>@item.Product.Name</div> <div>@item.Product.Description</div> <div><table> <tr><td>單價(jià):</td><td>@item.Product.Price</td> </tr> <tr><td>數(shù)量:</td><td> <input type="text" value="@item.Quantity" name="demo2" /></td> </tr> <tr><td>小計(jì):</td><td>@((item.Quantity * item.Product.Price).ToString("c"))</td> </tr></table> </div></div><div> <div>@using (Html.BeginForm("RemoveFromCart", "Home")){ @Html.Hidden("Id", item.Product.Id) @Html.HiddenFor(x => x.ReturnUrl) <input type="submit" value="移除"/> <a href="#" rel="external nofollow" role="button">查看</a>} </div></div> </div> } </div></div><hr/><div> <div><div> <span>總計(jì):</span> @Model.Cart.ComputeTotalPrice().ToString("c")</div><p align="left"> <a href="@Model.ReturnUrl" rel="external nofollow" >繼續(xù)購物</a></p> </div></div>@section scripts{ <script src="~/Scripts/jquery.bootstrap-touchspin.min.js"></script> <script type="text/javascript">$(function () { var i = $("input[class="demo2"]"); i.TouchSpin({min: 1,max: 100,step: 1//增量或減量 }); i.on("touchspin.on.stopupspin", function () {$.post("@Url.Action("IncreaseOrDecreaseOne", "Home")", { "id": $(this).closest("div.productbox").find("#Id").val(), "quantity": $(this).val() }, function (data) { if (data.msg) {location.reload(); }});//var temp = $(this).val();//alert(temp);//var temp = $(this).closest("div.productbox").find("#Id").val();//alert(temp); }); i.on("touchspin.on.stopdownspin", function () {$.post("@Url.Action("IncreaseOrDecreaseOne", "Home")", { "id": $(this).closest("div.productbox").find("#Id").val(), "quantity": $(this).val() }, function (data) { if (data.msg) {location.reload(); }}); });}); </script>}
在購物車頁,用了Bootstrap TouchSpin這款插件,點(diǎn)擊其中的數(shù)量的增量和減量按鈕,就向Home控制器中的IncreaseOrDecreaseOne方法發(fā)送一個(gè)異步post請求,得到返回?cái)?shù)據(jù)刷新購物車頁。
//點(diǎn)擊數(shù)量+號(hào)或點(diǎn)擊數(shù)量-號(hào)或自己輸入一個(gè)值[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 });}
在購車頁,點(diǎn)擊"移除"按鈕,就向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中加載部分視圖而來。
<head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> @Styles.Render("~/Content/css") <link href="~/bootstrap/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet" /> @RenderSection("styles", required: false) @Scripts.Render("~/bundles/jquery") <script src="~/bootstrap/js/bootstrap.min.js"></script></head><body> @{Html.RenderAction("Summary", "Home");} @RenderBody() @RenderSection("scripts", required: false)</body>
在Home控制器中,對應(yīng)的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是一個(gè)有關(guān)Cart的強(qiáng)類型部分視圖:
@model MvcApplication1.Models.Cart@{ Layout = null;}<div id="cart"> <span><b>購物車明細(xì):</b>@if (Model != null){ @Model.Lines.Sum(x => x.Quantity) <span>件,</span> @Model.ComputeTotalPrice().ToString("c")} </span> @Html.ActionLink("結(jié)算", "CartIndex", "Home", new {returnUrl = Request.Url.PathAndQuery}, null) @Html.ActionLink("清空", "EmptyCart", "Home", new {returnUrl = Request.Url.PathAndQuery}, null)</div>
注意:需要把Layout設(shè)置為null,否則會(huì)報(bào)錯(cuò),因?yàn)楫a(chǎn)品選購頁和購物車摘要同時(shí)加載Views/Shared/_Layout.cshtml就反復(fù)調(diào)用了。
到此這篇關(guān)于ASP.NET MVC實(shí)現(xiàn)橫向展示購物車的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持。
相關(guān)文章:
1. ASP.NET MVC通過勾選checkbox更改select的內(nèi)容2. 原生js實(shí)現(xiàn)購物車功能3. js實(shí)現(xiàn)購物車計(jì)算的方法4. ASP.NET MVC使用JSAjaxFileUploader插件實(shí)現(xiàn)單文件上傳5. ASP.NET MVC視圖頁使用jQuery傳遞異步數(shù)據(jù)的幾種方式詳解6. ASP.NET MVC增加一條記錄同時(shí)添加N條集合屬性所對應(yīng)的個(gè)體7. ASP.NET MVC解決上傳圖片臟數(shù)據(jù)的方法8. ASP.NET MVC前臺(tái)動(dòng)態(tài)添加文本框并在后臺(tái)使用FormCollection接收值9. ASP.NET MVC實(shí)現(xiàn)單個(gè)圖片上傳、限制圖片格式與大小并在服務(wù)端裁剪圖片10. ASP.NET MVC使用Boostrap實(shí)現(xiàn)產(chǎn)品展示、查詢、排序、分頁
