SportsStore是《精通ASP.NET MVC3框架(第三版)》中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器、URL优化、导航、分页、购物车、订单、产品管理、图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离。本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能。
本篇为"在三层架构下实现SportsStore"系列的第十一篇,包括:
■ 13、使用Knockout实现增删改查
□ 13.1 关于Knockout
□ 13.2 实现增删改查
13、使用Knockout实现增删改查
13.1 关于Knockout
在ASP.NET MVC中,拿一个强类型视图页来说,视图View和Model有着比较强的耦合。Knockout的出现就是为了解耦View和Model。Knockout是一个Javascript库,他通过创建View Model,实现了View和Model之间的解耦,这符合基于UI的设计模式"MVVM":
● Model: 应用程序的领域模型(Domain Model),在Knockout中,经常使用Ajax对领域模型进行读写。
● View: 动态显示或更新View Model的UI
● View Model: 在UI层的JavaScript对象,UI层的Model。
关于Knockout,请参考官网。http://knockoutjs.com/index.html
13.2 实现增删改查
在ProductManage控制器中实现增删改查的逻辑:
using System.Linq; using System.Web.Mvc; using MySportsStore.IBLL; using MySportsStore.Model; using Ninject; namespace MySportsStore.WebUI.Controllers { public class ProductManageController : BaseController { [Inject] public IProductService ProductService { get; set; } public ProductManageController() { this.AddDisposableObject(ProductService); } public ActionResult Index() { return View(); } public JsonResult GetProducts() { return Json(ProductService.LoadEntities(p => true), JsonRequestBehavior.AllowGet); } public JsonResult AddProduct(Product product) { ProductService.AddEntity(product); return Json(product, JsonRequestBehavior.AllowGet); } public JsonResult EditProduct(Product product) { ProductService.UpdateEntity(product); return Json(ProductService.LoadEntities(p => true), JsonRequestBehavior.AllowGet); } public JsonResult DeleteProduct(int id) { var dbProduct = ProductService.LoadEntities(p => p.Id == id).FirstOrDefault(); if (ProductService.DeleteEntity(dbProduct) > 0) { return Json(new {msg = true},JsonRequestBehavior.AllowGet); } return Json(new { msg = false }, JsonRequestBehavior.AllowGet); } } }
在ProductManage/Index.cshtml视图中:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <style type="text/css"> //省去样式 </style> <script src="~/Scripts/jquery-1.8.2.min.js"></script> <script src="~/Scripts/knockout-3.1.0.js"></script> <script type="text/javascript"> $(function() { var viewModel = new ProductViewModel(); ko.applyBindings(viewModel); }); function ProductViewModel() { var self = this; //让属性observalbe self.Id = ko.observable(""); self.Name = ko.observable(""); self.Description = ko.observable(""); self.Price = ko.observable(""); self.Category = ko.observable(""); var Product = { Id: self.Id, Name: self.Name, Description: self.Description, Price: self.Price, Category: self.Category }; self.Product = ko.observable(); self.Products = ko.observableArray(); //初始化产品列表 $.ajax({ url: '@Url.Action("GetProducts","ProductManage")', cache: false, type: 'GET', contentType: 'application/json; charset=utf-8', data: {}, success: function(data) { self.Products(data); } }); //初始化之后计算总价,增加一个计算属性 self.Total = ko.computed(function() { var sum = 0; var arr = self.Products(); for (var i = 0; i < arr.length; i++) { sum += arr[i].Price; } return sum; }); //添加 self.create = function() { if (Product.Name() != "" && Product.Price() != "" && Product.Description() != "" && Product.Category() != "") { $.ajax({ url: '@Url.Action("AddProduct","ProductManage")', cache: false, type: 'POST', contentType: 'application/json; charset=utf-8', data: ko.toJSON(Product), success: function(data) { self.Products.push(data); //清空 self.Name(""); self.Description(""); self.Price(""); self.Category(""); } }).fail(function(xhr, textStatus, err) { alert(err); }); } else { alert("不能为空~~"); } }; //删除 self.delete = function(Product) { if (confirm('确定要删除 "' + Product.Name + '" 吗')) { //var id = Product.Id; $.ajax({ url: '@Url.Action("DeleteProduct","ProductManage")', cache: false, type: 'GET', contentType: 'application/json; charset=utf-8', //data: ko.toJSON(id), data: {id : Product.Id }, success: function(data) { if (data.msg == true) { self.Products.remove(Product); } else { alert("服务器内部错误~~"); } } }).fail(function(xhr, textStatus, err) { alert("出错了~~"); }); } }; //显示更新界面 self.edit = function(Product) { self.Product(Product); }; //更新 self.update = function() { var Product = self.Product(); $.ajax({ url: '@Url.Action("EditProduct","ProductManage")', cache: false, type: 'POST', contentType: 'application/json; charset=utf-8', data: ko.toJSON(Product), success: function(data) { self.Products.removeAll(); self.Products(data); self.Product(null); alert("更新成功~~"); } }); }; //重置 self.reset = function() { self.Name(""); self.Price(""); self.Category(""); self.Description(""); }; //取消产品细节 self.cancel = function() { self.Product(null); }; } //格式化价格 function formatCurrency(value) { return "¥" + value.toFixed(2); } </script> </head> <body> <div id="body"> <h3>产品管理</h3> <table id="products1" data-bind=""> <thead> <tr> <th>编号</th> <th>产品名称</th> <th>产品描述</th> <th>产品类别</th> <th>价格</th> <th>操作</th> </tr> </thead> <tbody data-bind="foreach: Products"> <tr> <td data-bind="text: Id"></td> <td data-bind="text: Name"></td> <td data-bind="text: Description"></td> <td data-bind="text: Category"></td> <td data-bind="text: formatCurrency(Price)"></td> <td> <button data-bind="click: $root.edit">编辑</button> <button data-bind="click: $root.delete">删除</button> </td> </tr> </tbody> <tfoot> <tr> <td></td> <td></td> <td></td> <td>总计:</td> <td data-bind="text: formatCurrency($root.Total())"></td> <td></td> </tr> </tfoot> </table> <br/> <br/> <div style="border-top: solid 2px #282828; 430px; height: 10px"> </div> <div data-bind="if: Product"> <div><h2>更新产品</h2></div> <div> <label for="productId" data-bind="visible: false">编号</label> <label data-bind="text: Product().Id, visible: false"></label> </div> <div> <label for="name">产品名称</label> <input data-bind="value: Product().Name" type="text" title="Name"/> </div> <div> <label for="description">产品描述</label> <input data-bind="value: Product().Description" type="text" title="Description"/> </div> <div> <label for="category">产品类别</label> <input data-bind="value: Product().Category" type="text" title="Category"/> </div> <div> <label for="price">产品价格</label> <input data-bind="value: Product().Price" type="text" title="Price"/> </div> <br/> <div> <button data-bind="click: $root.update">更新</button> <button data-bind="click: $root.cancel">取消</button> </div> </div> <div data-bind="ifnot: Product()"> <div> <h2>添加产品</h2> </div> <div> <label for="name">产品名称</label> <input data-bind="value: $root.Name" type="text" title="Name" /> </div> <div> <label for="description">产品描述</label> <input data-bind="value: $root.Description" type="text" title="Description" /> </div> <div> <label for="category">产品类别</label> <input data-bind="value: $root.Category" type="text" title="Category" /> </div> <div> <label for="price">产品价格</label> <input data-bind="value: $root.Price" type="text" title="Price" /> </div> <div> <button data-bind="click: $root.create">添加</button> <button data-bind="click: $root.reset">重置</button> </div> </div> </div> </body> </html>
源码在这里。
“MVC项目实践,在三层架构下实现SportsStore”系列包括: