一步步打造一个简单的手动音量调节电商网站-书店(二)
本系列的开源代码库地址:https://github.com/liqingwen 2015/文.书店
《一步步打造一个简单的 MVC 电商网站 - BooksStore(一)》
《一步步打造一个简单的 MVC 电商网站 - BooksStore(二)》
《一步步打造一个简单的 MVC 电商网站 - BooksStore(三)》
《一步步打造一个简单的 MVC 电商网站 - BooksStore(四)》
简介
上一次我们尝试了:创建项目架构、创建域模型实体、创建单元测试、创建控制器与视图、创建分页和加入样式,而这一节我们会完成两个功能,分类导航与购物车。
主要功能与知识点如下:
分类、产品浏览、购物车、结算、CRUD(增删改查)管理、发邮件、分页、模型绑定、认证过滤器和单元测试等(预计剩余两篇,预计明天(因为周六不放假)和周三(因为周二不上班)发布)。
【备注】项目使用VS2015 C#6进行开发,有问题请发表在留言区哦,还有,页面长得比较丑,请见谅。
目录
添加分类导航
加入购物车
创建一个分部视图局部视图
一、添加分类导航
上一次我们把网页划分成了三个模块,其中左侧栏的部分尚未完成,左侧栏拥有将书籍分类展示的功能。
图一
1.回到之前的BookDetailsViewModels视图模型,我们额外再添加一个新的属性用作分类(当前类别):
///摘要///书籍详情视图模型////摘要公共类BookDetailsViewModels : pagin info { public IEnumerablebook { get;设置;} ///摘要///当前分类////汇总公共字符串CurrentCategory { get设置;} }2.修改完视图模型,现在就应该修改对应的图书控制器中的细节方法
///摘要///详情////summary///param name=' category '分类/param ///param name='pageIndex '页码/param////返回/返回公共操作结果详细信息(字符串类别,int page index=1){ var model=new BookDetailsViewModels { Books=_ book repository .书籍。其中(x=类别==空|| x。类别==类别)。订货人(x=x.Id).跳过((页面索引- 1) *页面大小)。Take(页面大小),CurrentCategory=类别,页面大小=页面大小,页面索引=页面索引,TotalItems=_ bookRepository .书。计数(x=类别==null | | x . Category==Category)};返回视图(模型);}BookController.cs
命名空间文书店。WebUI。控制器{公共类BookController :控制器{私有只读ibook repository _ book repository;public int page SiZe=5;公共图书管理员(ibook repository图书仓库){ _ book repository=图书仓库;} ///摘要///详情////summary///param name=' category '分类/param ///param name='pageIndex '页码/param////返回/返回公共操作结果详细信息(字符串类别,int page index=1){ var model=new BookDetailsViewModels { Books=_ book repository .书籍。其中(x=类别==空|| x。类别==类别)。订货人(x=x.Id).跳过((页面索引- 1) *页面大小)。Take(页面大小),CurrentCategory=类别,页面大小=页面大小,页面索引=页面索引,TotalItems=_ bookRepository .书。计数(x=类别==null | | x . Category==Category)};返回视图(模型);} }}参数增加了一个类别,用于获取分类的字符串,对应书中的属性的赋值语句改为_图书仓库.书籍。其中(x=类别==空|| x。类别==类别),这里的希腊字母的第11个表达式x=类别==空|| x。类别==类别的意思是,分类字符串为空就取库中所有的书实体,不为空时根据分类进行对集合进行筛选过滤。
还要对属性当前类别进行赋值。
别忘了,因为分页是根据合计项目属性进行的,所以还要修改地方_图书仓库.书籍。计数(x=类别==空|| x。类别==类别),通过LINQ统计不同分类情况的个数。
3.该控制器对应的Details.cshtml中的分页辅助器也需要修改,添加新的路由参数:
div class='pager' @Html .页面链接(模型,x=Url .操作('详细信息,新{页面索引=x,类别=模型. CurrentCategory }))/DivDetails。cshtml
@模特文书店。webui。模特。bookdetailsviewmodels @ { view bag .标题='书籍;}@foreach(模型中的定义变量项书籍){ div class=' item ' h3@item.Name/h3 @ item .描述h4@item .价格。ToString(' C ')/H4 br/HR//div } div class=' pager ' @ Html .页面链接(模型,x=Url .操作('详细信息,新{页面索引=x,类别=模型CurrentCategory }))/div4 .路由区域也应当修改一下
路由图铯
公共静态无效注册路由(常规选择路由){路线.忽略重路由(' {resource}).axd/{ * PathInfo } ');路线MapRoute(名称:‘Default’,URL :“{ controller }/{ action }”,Default s 3360 new { controller=‘Book’,action=‘Details’});路线MapRoute(name: null,URL : " { controller }/{ action }/{ category } ",默认s 3360 new { controller=' Book ',action=' Details ' });路线MapRoute(name: null,URL : " { controller }/{ action }/{ category }/{ page index } ",默认s 3360 new { controller=' Book ',action='Details ',pageIndex=UrlParameter .可选});}5.现在新建一个名为导航控制器的控制器,并添加一个名为补充报道的方法,专门用于渲染左侧边栏。
不过返回的视角视图类型变成PartialView分部视图类型:
public PartialViewResult侧边栏(字符串类别=null){ var categories=_ book repository .书籍。选择(x=x。类别)。独特的.排序依据(x=x);返回PartialView(类别);}在方法体在右键,添加一个视图,勾上创建分部视图。
侧边栏。cshtml修改为:
@ model IEnumerablestingul Li @ Html .ActionLink('所有分类、"详细信息"、"图书"/li @foreach(模型中的定义变量项目){ li@Html .RouteLink(item,new { controller='Book ',action='Details ',category=item,pageIndex=1 },new { @ class=item==ViewBag .当前类别?所选的: null })/Li }/乌尔姆VC框架具有一种叫作"子动作(儿童行动)"的概念,可以适用于重用导航控件之类的东西,使用类似RenderAction()的方法,在当前的视图中输出指定的动作方法。
因为需要在父视图中呈现另一个行动中的分部视图,所以原来的_Layout.cshtml布局页修改如下:
现在,启动的结果应该和图一是一样的,尝试点击左侧边栏的分类,观察主区域的变化情况。
二、加入购物车
图2
界面的大体功能如图2,在每本图书的区域新增一个链接(添加到购物车),会跳转到一个新的页面,显示购物车的详细信息-购物清单,也可以通过"结算"链接跳转到一个新的页面。
购物车是应用程序业务域的一部分,因此,购物车实体应该为域模型。
1.添加两个类:
购物车。铯有添加、移除、清空和统计功能:
///摘要///购物车////摘要公共类cart { private readonly list cartiem _ cartiems=new list cartiem();///摘要///获取购物车的所有项目////summary public ilist artitem getcartiems=_ cartiems;///摘要///添加书模型////summary////param name=' Book '/param///param name=' quantity '/param public void AddBook(Book Book,int quantity){ if(_ cartiems).count==0){ _ Cartiems .添加(新卡地亚(){书=书,量=量});返回;} var模型=_cartItems .first ordefault(x=x . book。id==book .id);if(model==null){ _ Cartiems .添加(新卡地亚(){书=书,量=量});返回;}型号。数量=数量;} ///摘要///移除书模型////摘要///param name=' Book '/param public void remove Book(Book Book){ var model=_ cartiems .first ordefault(x=x . book。id==book .id);if(model==null){ return;} _cartItems .RemoveAll(x=x.Book.Id==book .id);} ///摘要///清空购物车////摘要公共void Clear(){ _ cartiems .clear();} ///摘要///统计总额////summary///returns/returns public decimal ComputeTotalValue(){ return _ cartiems .总和(x=x。账面价格* x。数量);} } CartItem.cs表示购物车中的每一项:
///摘要///购物车项////摘要公共类cartiem {///摘要///书////汇总公共预订预订设置;} ///摘要///数量////汇总公共int Quantity { get设置;} }2.修改一下之前的Details.cshtml,增加"添加到购物车"的按钮:
@模特文书店。webui。模特。bookdetailsviewmodels @ { view bag .标题='书籍;}@foreach(模型中的定义变量项书籍){ div class=' item ' h3@item.Name/h3 @ item .描述h4@item .价格。ToString(' C ')/H4 @使用(Html .开始通知(“添加到购物车”,“购物车”){ var id=item .id;@Html .hidden FOr(x=id);@Html .隐藏('返回Url ',请求Url。路径和查询)输入类型='提交'值='添加到购物车/} br/HR//div } div class=' pager ' @ Html .页面链接(模型,x=Url .操作('详细信息,新{页面索引=x,类别=模型CurrentCategory }))/div【备注】@Html .BeginForm()方法默认会创建一个邮政请求方法的表单,为什么不直接使用得到请求呢,HTTP规范要求,会引起数据变化时不要使用得到请求,将产品添加到一个购物车明显会出现新的数据变化,所以,这种情形不应该使用得到请求,直接显示页面或者列表数据,这种请求才应该使用得到。
3.先修改下钢性铸铁中的样式
正文{ } #标题,#内容,#侧边栏{ display : block } # header { background-color :绿色;边框-底部: 2px实心# 111;颜色:白色;} #标题,title { font-size : 1.5 empadding:5em } #侧边栏{左侧浮动:宽度: 8毫米;padding:3em } #内容{边框-左侧: 2px纯灰色;左边距: 10毫米;padding: 1em }。寻呼机{ text-align : right划水:5万;页边距-top : 1em;} .传呼机A { font-size : 1.1 em颜色: # 666划水0 .4em 0 .4em}。呼叫器A:hover {背景色-银色:} .寻呼机a .选中{底色: # 353535;颜色:白色;}.项目输入{右侧浮动:颜色:白色;背景-颜色:绿色;}.表{宽度: 100%;padd : 0;保证金: 0;} .表Helvetica阿里亚尔凡尔达纳,无衬线;color : # 4f 6b 72 border-right : 1px实心# C1DAD7边框-bottom: 1px实心# C1DAD7边框-top: 1px实心# C1DAD7字母间距2 xtext-transform :大写;文本-左对齐:padding: 6px 6px 6px 12px背景: #CAE8EA不重复;} .表td {边框-右侧: 1px实心# C1DAD7边框-bottom: 1px实心# C1DAD7背景# fffont-size : 14px;padd : 6px 6px 6px 12pxcolor 3360 # 4f 6b 72 }。表TD . alt { background : # f5Fafacolor : # 797268 }。表th.spec,td.spec {边框-左侧: 1px实心# C1DAD7}4。再添加一个CartController
///摘要///购物车////摘要公共类购物车控制器:控制器{私有只读ibook存储库_图书存储库;公共购物车控制器(ibook repository book repository){ _ book repository=book repository;} ///摘要///首页////summary////param name=' return URL '/param////return/return public View结果Index(字符串返回URL){返回视图(new cardendexviewmodel(){ Cart=GetCart(),返回URL=返回URL });} ///摘要///添加到购物车////summary////param name=' id '/param///param name=' return URl '/param///returns/returns/返回public RedirectToRouteResult add to cart(int id,字符串返回URl){ var book=_ book repository .书籍。first or default(x=x . Id==Id);如果(书!=null) { GetCart().AddBook(book,1);}返回RedirectToAction('Index ',new { return URL });} ///摘要///从购物车移除////summary////param name=' id '/param///param name=' return URl '/param///return/return public redirecttoroutreault remove from cart(int id,string return URl){ var book=_ book repository .书籍。first or default(x=x . Id==Id);如果(书!=null) { GetCart().RemoveBook(图书);}返回RedirectToAction('Index ',new { return URL });} ///摘要///获取购物车////summary////returns/returns private Cart GetCart(){ var Cart=(Cart)Session[' Cart '];如果(推车!=null)返回购物车;Cart=新Cart();会话['购物车']=购物车;返回推车;} }【备注】这里的购物车是通过会议会话状态进行保存用户的手推车对象。当会话过期(典型的情况是用户很长时间没有对服务器发起任何请求),与该会话关联的数据就会被删除,这就意味着不需要对手推车对象进行生命周期的管理。
【备注】RedirectToAction()方法:将一个超文本传送协议重定向的指令发给客户端浏览器,要求浏览器请求一个新的Url。
5.在索引方法中选择右键新建视图,专门用于显示购物清单:
Index.cshtml中的代码:
@模特文书店。webui。模特。cardindexviewmodel 2我的购物车/h2table class='table '和tr th书名/th价格/th数量/th总计/th/tr/the和tbody @foreach(模型中的定义变量项目。td@item.Book.Name/tdtd@item.Book.Price/td TD @ item。数量/td .预订。价格*项目。数量)。ToString(' C ')/TD/tr } tr TD/TD TD/TD TD总计:/td td@Model .推车。ComputeTotalValue().' ToString(' C ')/TD/tr/t body/tablep a href=' @ Model . '' ReturnUrl '继续购物/a/p我想,这一定是一个令人激动的时刻,因为我们已经完成了这个基本的添加到购物车的功能。
三、创建一个分部视图局部视图
分部视图,是嵌入在另一个视图中的一个内容片段,并且可以跨视图重用,这有助于减少重复,尤其需要在多个地方需要重复使用相同的数据时。
在共享的内部新建一个名为_BookSummary.cshtml的视图,并且把之前Details.cshtml的代码进行整理。
修改后的两个视图:
Details.cshtml
@模特文书店。webui。模特。bookdetailsviewmodels @ { view bag .标题='书籍;}@foreach(模型中的定义变量项。书籍){ Html .RenderPartial('_BookSummary ',item);}div class='pager' @Html .页面链接(模型,x=Url .操作('详细信息,新{页面索引=x,类别=模型.当前类别}))/div _ booksummary。cshtml
@模特文h3 @型号。名称/h3 @模型。描述h4 @型号价格。ToString(' C ')/H4 @使用(Html .开始通知('添加到购物车','购物车'){ var id=Model .id;@Html .hidden FOr(x=id);@Html .隐藏('返回Url ',请求Url。路径和查询)输入类型='提交'值='添加到购物车/} br/hr //div以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。