您现在的位置是:网站首页> 编程资料编程资料

一步步打造简单的MVC电商网站BooksStore(2)_实用技巧_

2023-05-24 390人已围观

简介 一步步打造简单的MVC电商网站BooksStore(2)_实用技巧_

一步步打造一个简单的 MVC 电商网站 - BooksStore(二)

本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore

一步步打造一个简单的 MVC 电商网站 - BooksStore(一)

一步步打造一个简单的 MVC 电商网站 - BooksStore(二)

一步步打造一个简单的 MVC 电商网站 - BooksStore(三)

一步步打造一个简单的 MVC 电商网站 - BooksStore(四)

简介

上一次我们尝试了:创建项目架构、创建域模型实体、创建单元测试、创建控制器与视图、创建分页和加入样式,而这一节我们会完成两个功能,分类导航与购物车。

主要功能与知识点如下:

分类、产品浏览、购物车、结算、CRUD(增删改查) 管理、发邮件、分页、模型绑定、认证过滤器和单元测试等(预计剩余两篇,预计明天(因为周六不放假)和周三(因为周二不上班)发布)。

【备注】项目使用 VS2015 + C#6 进行开发,有问题请发表在留言区哦,还有,页面长得比较丑,请见谅。

目录

添加分类导航

加入购物车

创建一个分部视图 Partial View

一、添加分类导航

上一次我们把网页划分成了三个模块,其中左侧栏的部分尚未完成,左侧栏拥有将书籍分类展示的功能。

图 1

1.回到之前的BookDetailsViewModels 视图模型,我们额外再添加一个新的属性用作分类(CurrentCategory):

 ///  /// 书籍详情视图模型 ///  public class BookDetailsViewModels : PagingInfo { public IEnumerable Books { get; set; } ///  /// 当前分类 ///  public string CurrentCategory { get; set; } } 

2.修改完视图模型,现在就应该修改对应的 BookController 中的Details 方法

 ///  /// 详情 ///  /// 分类 /// 页码 ///  public ActionResult Details(string category, int pageIndex = 1) { var model = new BookDetailsViewModels { Books = _bookRepository.Books.Where(x => category == null || x.Category == category) .OrderBy(x => x.Id) .Skip((pageIndex - 1) * PageSize) .Take(PageSize), CurrentCategory = category, PageSize = PageSize, PageIndex = pageIndex, TotalItems = _bookRepository.Books.Count(x => category == null || x.Category == category) }; return View(model); } 

BookController.cs 

 namespace Wen.BooksStore.WebUI.Controllers { public class BookController : Controller { private readonly IBookRepository _bookRepository; public int PageSize = 5; public BookController(IBookRepository bookRepository) { _bookRepository = bookRepository; } ///  /// 详情 ///  /// 分类 /// 页码 ///  public ActionResult Details(string category, int pageIndex = 1) { var model = new BookDetailsViewModels { Books = _bookRepository.Books.Where(x => category == null || x.Category == category) .OrderBy(x => x.Id) .Skip((pageIndex - 1) * PageSize) .Take(PageSize), CurrentCategory = category, PageSize = PageSize, PageIndex = pageIndex, TotalItems = _bookRepository.Books.Count(x => category == null || x.Category == category) }; return View(model); } } } 

参数增加了一个 category,用于获取分类的字符串,对应 Books 中的属性的赋值语句改为_bookRepository.Books.Where(x => category == null || x.Category == category),这里的 Lambda 表达式x => category == null || x.Category ==category 的意思是,分类字符串为空就取库中所有的 Book 实体,不为空时根据分类进行对集合进行筛选过滤。

还要对属性 CurrentCategory 进行赋值。

别忘了,因为分页是根据 TotalItems 属性进行的,所以还要修改地方_bookRepository.Books.Count(x => category == null || x.Category == category),通过 LINQ 统计不同分类情况的个数。

3.该控制器对应的 Details.cshtml 中的分页辅助器也需要修改,添加新的路由参数:

@Html.PageLinks(Model, x => Url.Action("Details", new { pageIndex = x, category = Model.CurrentCategory }))

Details.cshtml

 @model Wen.BooksStore.WebUI.Models.BookDetailsViewModels @{ ViewBag.Title = "Books"; } @foreach (var item in Model.Books) { 

@item.Name

@item.Description

@item.Price.ToString("C")



}
@Html.PageLinks(Model, x => Url.Action("Details", new { pageIndex = x, category = Model.CurrentCategory }))

4.路由区域也应当修改一下

RouteConfig.cs

 public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}", defaults: new { controller = "Book", action = "Details" } ); routes.MapRoute( name: null, url: "{controller}/{action}/{category}", defaults: new { controller = "Book", action = "Details" } ); routes.MapRoute( name: null, url: "{controller}/{action}/{category}/{pageIndex}", defaults: new { controller = "Book", action = "Details", pageIndex = UrlParameter.Optional } ); } 

5.现在新建一个名为 NavController 的控制器,并添加一个名为Sidebar 的方法,专门用于渲染左侧边栏。

不过返回的 View 视图类型变成 PartialView 分部视图类型:

 public PartialViewResult Sidebar(string category = null) { var categories = _bookRepository.Books.Select(x => x.Category).Distinct().OrderBy(x => x); return PartialView(categories); } 

在方法体在右键,添加一个视图,勾上创建分部视图。

Sidebar.cshtml 修改为:

 @model IEnumerable
  • @Html.ActionLink("所有分类", "Details", "Book")
  • @foreach (var item in Model) {
  • @Html.RouteLink(item, new { controller = "Book", action = "Details", category = item, pageIndex = 1 }, new { @class = item == ViewBag.CurrentCategory ? "selected" : null })
  • }

MVC 框架具有一种叫作“子动作(Child Action)”的概念,可以适用于重用导航控件之类的东西,使用类似 RenderAction() 的方法,在当前的视图中输出指定的动作方法。

因为需要在父视图中呈现另一个 Action 中的分部视图,所以原来的_Layout.cshtml布局页修改如下:

现在,启动的结果应该和图 1 是一样的,尝试点击左侧边栏的分类,观察主区域的变化情况。

二、加入购物车

图 2

界面的大体功能如图 2,在每本图书的区域新增一个链接(添加到购物车),会跳转到一个新的页面,显示购物车的详细信息 - 购物清单,也可以通过“结算”链接跳转到一个新的页面。

购物车是应用程序业务域的一部分,因此,购物车实体应该为域模型。

1.添加两个类:

Cart.cs 有添加、移除、清空和统计功能:

 ///  /// 购物车 ///  public class Cart { private readonly List _cartItems = new List(); ///  /// 获取购物车的所有项目 ///  public IList GetCartItems => _cartItems; ///  /// 添加书模型 ///  ///  ///  public void AddBook(Book book, int quantity) { if (_cartItems.Count == 0) { _cartItems.Add(new CartItem() { Book = book, Quantity = quantity }); return; } var model = _cartItems.FirstOrDefault(x => x.Book.Id == book.Id); if (model == null) { _cartItems.Add(new CartItem() { Book = book, Quantity = quantity }); return; } model.Quantity += quantity; } ///  /// 移除书模型 ///  ///  public void RemoveBook(Book book) { var model = _cartItems.FirstOrDefault(x => x.Book.Id == book.Id); if (model == null) { return; } _cartItems.RemoveAll(x => x.Book.Id == book.Id); } ///  /// 清空购物车 ///  public void Clear() { _cartItems.Clear(); } ///  /// 统计总额 ///  ///  public decimal ComputeTotalValue() { return _cartItems.Sum(x => x.Book.Price * x.Quantity); } } 

CartItem.cs 表示购物车中的每一项:

 ///  /// 购物车项 ///  public class CartItem { ///  /// 书 ///  public Book Book { get; set; } ///  /// 数量 ///  public int Quantity { get; set; } } 

2.修改一下之前的 Details.cshtml,增加“添加到购物车”的按钮:

 @model Wen.BooksStore.WebUI.Models.BookDetailsViewModels @{ ViewBag.Title = "Books"; } @foreach (var item in Model.Books) { 

@item.Name

@item.Description

@item.Price.ToString("C")

@using (Html.BeginForm("AddToCart", "Cart")) { var id = item.Id; @Html.HiddenFor(x => id); @Html.Hidden("returnUrl", Request.Url.PathAndQuery) }

}
@Html.PageLinks(Model, x => Url.Action("Details", new { pageIndex = x, category = Model.CurrentCategory }))

【备注】@Html.BeginForm() 方法默认会创建一个 Post 请求方法的表单,为什么不直接使用 Get 请求呢,HTTP 规范要求,会引起数据变化时不要使用 Get 请求,将产品添加到一个购物车明显会出现新的数据变化,所以,这种情形不应该使用 Get 请求,直接显示页面或者列表数据,这种请求才应该使用 Get。

3.先修改下 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%;
                
                

-六神源码网