<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
通常,我們看到的購物車是這樣的:
雖然這種購物車顯示方式被廣泛運用,但我個人覺得不夠直觀。如果換成這樣呢?
本篇的原始碼放在了:https://github.com/darrenji/ShoppingCartInMVC
以上購物車頁能實現的效果包括:
1、購物車明細:顯示訂購數量、總金額,清空購物車。
2、購物車內產品:數量可調整,對應的小計和總計動態變化。點選移除按鈕移除該產品。
3、繼續購物按鈕:點選左下角的繼續購物按鈕,回到先前頁。
4、使用了Bootstrap, 頁面元素自適應,頁面寬度調小時,頁面佈局動態變化。
5、每行放置4個產品,且允許高度不一致,第5個產品另起一行,且不會float到上一行的空白區域,如下圖。
首先,有關產品的類。
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; } }
產品選購頁如圖:
以上,產品選購頁是一個有關Product集合的強型別檢視頁,其對應的Model為:
public class ProductsListVm { public ProductsListVm() { this.Products = new List<Product>(); } public IEnumerable<Product> Products { get; set; } }
想像一下,我們在超市購物,在購物車內放著不同的商品對應不同的數量,在這裡,可以把商品和數量抽象成一個類:
public class CartLine { public Product Product { get; set; } public int Quantity { get; set; } }
而購物車類實際上就是維護著這個CartLine集合,需要提供新增、移除、計算購物車總價、清空購物車等方法,並提供一個獲取到CartLine集合的屬性,另外,針對點選購物車頁上的增量和減量按鈕,也要提供相應的方法。
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; } } //點選數量+號或點選數量-號或自己輸入一個值 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<CartLine> 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<Product> GetAllProducts() { return new List<Product>() { 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"; } <style type="text/css"> .item { border-bottom: solid 1px gray; } </style> <div class="container"> <div class="row"> @foreach (var item in Model.Products) { Html.RenderPartial("ProductSummary", item); } </div> </div>
其中,遍歷Product集合的時候,又去載入Views/Shared/ProductSummary.cshtml這個強型別部分檢視。
@model MvcApplication1.Models.Product <div class="item"> <h3>@Model.Name</h3> <p><img src="@Model.ImageUrl" style="width: 100px;height: 100px;"/></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>
點選"+放入購物車"按鈕,呼叫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 { <link href="~/Content/shopitem.css" rel="external nofollow" rel="stylesheet" /> <link href="~/Content/jquery.bootstrap-touchspin.min.css" rel="external nofollow" rel="stylesheet" /> } <div class="container"> <div class="row"> @for (int i = 0; i < Model.Cart.Lines.Count(); i++) { var item = (Model.Cart.Lines.ToList())[i]; if (i != 0 && i%4 == 0) //每行有4個div { <div style="clear:both;"></div> } <div class="col-md-3 column productbox"> <img src="@item.Product.ImageUrl" style="width: 460px; height: 250px;" class="img-responsive"> <div class="producttitle"> <div class="productname">@item.Product.Name</div> <div class="productdes">@item.Product.Description</div> <div> <table> <tr> <td style="width:50px;">單價:</td> <td>@item.Product.Price</td> </tr> <tr> <td>數量:</td> <td> <input class="demo2" type="text" value="@item.Quantity" name="demo2" /> </td> </tr> <tr> <td>小計:</td> <td>@((item.Quantity * item.Product.Price).ToString("c"))</td> </tr> </table> </div> </div> <div class="productprice"> <div class="text-center"> @using (Html.BeginForm("RemoveFromCart", "Home")) { @Html.Hidden("Id", item.Product.Id) @Html.HiddenFor(x => x.ReturnUrl) <input class="btn btn-default btn-sm" type="submit" value="移除"/> <a href="#" rel="external nofollow" class="btn btn-danger btn-sm" role="button">檢視</a> } </div> </div> </div> } </div> </div> <hr/> <div class="container"> <div class="row"> <div class="text-center" style="font-size: 55px;font-weight: bold;color: red;"> <span>總計:</span> @Model.Cart.ComputeTotalPrice().ToString("c") </div> <p align="left" class="actionButtons" style="width: 100%; clear: both"> <a href="@Model.ReturnUrl" rel="external nofollow" >繼續購物</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這款外掛,點選其中的數量的增量和減量按鈕,就向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中載入部分檢視而來。
<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控制器中,對應的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; } <div id="cart" style="background-color: #e3e3e3;padding: 10px; text-align:center;"> <span class="caption"> <b>購物車明細:</b> @if (Model != null) { @Model.Lines.Sum(x => x.Quantity) <span>件,</span> @Model.ComputeTotalPrice().ToString("c") } </span> @Html.ActionLink("結算", "CartIndex", "Home", new {returnUrl = Request.Url.PathAndQuery}, null) @Html.ActionLink("清空", "EmptyCart", "Home", new {returnUrl = Request.Url.PathAndQuery}, null) </div>
注意:需要把Layout設定為null,否則會報錯,因為產品選購頁和購物車摘要同時載入Views/Shared/_Layout.cshtml就反覆呼叫了。
到此這篇關於ASP.NET MVC實現橫向展示購物車的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45