一步步打造一个简单的 MVC 电商网站 - BooksStore(三)
本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore
《一步步打造一个简单的 MVC 电商网站 - BooksStore(一)》
《一步步打造一个简单的 MVC 电商网站 - BooksStore(二)》
《一步步打造一个简单的 MVC 电商网站 - BooksStore(三)》
《一步步打造一个简单的 MVC 电商网站 - BooksStore(四)》
简介
上一节我们完成了两个主要功能:添加到购物车和分类导航,这一节我们会完成整个购物车的流程,以及订单处理。
该系列主要功能与知识点如下:
分类、产品浏览、购物车、结算、CRUD(增删改查) 管理、发邮件、分页、模型绑定、认证过滤器和单元测试等(预计剩余两篇,周三(因为周二不上班)先发布一篇)。
【备注】项目使用 VS2015 + C#6 进行开发,有问题请发表在留言区哦,还有,页面长得比较丑,请见谅。
目录
完成购物车
订单结算
一、完成购物车
上一节其实已经完成了移除购物车和清空购物车的方法,只是尚未将可供用户操作的按钮放在页面区域。除了增加这两个按钮,也会在页面顶部的位置增加购物车的摘要(用于显示用户的购物总额)。
下面是上一节已经写好的 CartController 代码。
/// <summary>
/// 购物车
/// </summary>
public class CartController : Controller
{
private readonly IBookRepository _bookRepository;
public CartController(IBookRepository bookRepository)
{
_bookRepository = bookRepository;
}
/// <summary>
/// 首页
/// </summary>
/// <param name="returnUrl"></param>
/// <returns></returns>
public ViewResult Index(string returnUrl)
{
return View(new CartIndexViewModel()
{
Cart = GetCart(),
ReturnUrl = returnUrl
});
}
/// <summary>
/// 添加到购物车
/// </summary>
/// <param name="id"></param>
/// <param name="returnUrl"></param>
/// <returns></returns>
public RedirectToRouteResult AddToCart(int id, string returnUrl)
{
var book = _bookRepository.Books.FirstOrDefault(x => x.Id == id);
if (book != null)
{
GetCart().AddBook(book, 1);
}
return RedirectToAction("Index", new { returnUrl });
}
/// <summary>
/// 从购物车移除
/// </summary>
/// <param name="id"></param>
/// <param name="returnUrl"></param>
/// <returns></returns>
public RedirectToRouteResult RemoveFromCart(int id, string returnUrl)
{
var book = _bookRepository.Books.FirstOrDefault(x => x.Id == id);
if (book != null)
{
GetCart().RemoveBook(book);
}
return RedirectToAction("Index", new { returnUrl });
}
/// <summary>
/// 获取购物车
/// </summary>
/// <returns></returns>
private Cart GetCart()
{
var cart = (Cart)Session["Cart"];
if (cart != null) return cart;
cart = new Cart();
Session["Cart"] = cart;
return cart;
}
}
</div>
1.加入移除书籍和清空购物车的功能

Index.cshtml
@model Wen.BooksStore.WebUI.Models.CartIndexViewModel
<h2>我的购物车</h2>
<table class="table">
<thead>
<tr>
<th>书名</th>
<th>价格</th>
<th>数量</th>
<th>总计</th>
<th> </th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Cart.GetCartItems)
{
<tr>
<td>@item.Book.Name</td>
<td>@item.Book.Price</td>
<td>@item.Quantity</td>
<td>@((item.Book.Price * item.Quantity).ToString("C"))</td>
<td>
@using (Html.BeginForm("RemoveFromCart", "Cart"))
{
@Html.Hidden("id", item.Book.Id)
@Html.HiddenFor(x => x.ReturnUrl)
<input type="submit" value="- 移除" />
}
</td>
</tr>
}
<tr>
<td> </td>
<td> </td>
<td>总计:</td>
<td>@Model.Cart.ComputeTotalValue().ToString("C")</td>
<td>
@using (Html.BeginForm("Clear", "Cart"))
{
@Html.HiddenFor(x => x.ReturnUrl)
<input type="submit" value="清空购物车" />
}
</td>
</tr>
</tbody>
</table>
</div>
【备注】@Html.Hidden("id", item.Book.Id) 是用于生成隐藏的字段,如果直接使用@Html.HiddenFor(),生成的 name 将会是 item.Book.Id ,将和 CartController 中 RemoveFromCart(int id, string return) 的参数不匹配。
显示的效果如下:

2.添加摘要:我们在购物车存放了许多东西,通过摘要,可以显示购物总额的缩略图,我们选择的位置在顶部右上角的一个比较显眼的位置进行显示它,当然,还需要有点击的跳转按钮方便显示所有的购物清单页面。
继续在 CartController 下新增一个 Action,名为 Summary,返回值是一个分部视图:
/// <summary>
/// 摘要
/// </summary>
/// <returns></returns>
public PartialViewResult Summary()
{
return PartialView(GetCart());
}
</div>
对应的Summary.cshtml
@model Wen.BooksStore.Domain.Entities.Cart
<div class="bookSummary">
你的购物车:@Model.ComputeTotalValue()
<span>@Html.ActionLink("结算", "Checkout", "Cart", new { retunUrl = Request.Url.PathAndQuery }, null)</span>
</div>
</div>
对应的布局页_Layout.cshtml 修改的地方为:

_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<link href="~/Contents/Site.css" rel="stylesheet" />
</head>
<body>
<div id="header">
@{ Html.RenderAction("Summary", "Cart");}
<div class="title">图书商城</div>
</div>
<div id="sideBar">
@{ Html.RenderAction("Sidebar", "Nav"); }
</div>
<div id="content">
@RenderBody()
</div>
</body>
</html>
</div>
添加了新的东西,css 也要进行修改:
Site.css
body {
}
#header, #content, #sideBar {
display: block;
}
#header {
background-color: green;
border-bottom: 2px solid #111;
color: White;
}
#header, .title {
font-size: 1.5em;
padding: .5em;
}
#sideBar {
float: left;
width: 8em;
padding: .3em;
}
#content {
border-left: 2px solid gray;
margin-left: 10em;
padding: 1em;
}
.pager {
text-align: right;
padding: .5em 0 0 0;
margin-top: 1em;
}
.pager A {
font-size: 1.1em;
color: #666;
padding: 0 .4em 0 .4em;
}
.pager A:hover {
background-color: Silver;
}
.pager A.selected {
background-color: #353535;
color: White;
}
.item input {
float: right;
color: White;
background-color: green;
}
.table {
width: 100%;
padding: 0;
margin: 0;
}
.table th {
font: bold 12px "Trebuchet MS", Verdana, Arial, Helvet

