天天看點

Orchard子產品開發全接觸4:深度改造前台

這裡,我們需要做一些事情,這些事情意味着深度改造前台:

1:為商品增加 添加到購物車 按鈕,點選後功能實作;

2:商品排序;

3:購物車預覽,以及添加 結算 按鈕;

4:一個顯式 購物車中有*個 商品 的widget;

一:添加到購物車 按鈕

修改 Views/Parts/Product.cshtml:

@{     var price = (decimal)Model.Price;     var sku = (string)Model.Sku; } <article>     Price: @price<br />     Sku: @sku     <footer>         <button>Add to shoppingcart</button>     </footer> </article>

現在,商品清單上已經有了這個按鈕:

Orchard子產品開發全接觸4:深度改造前台

包括商品詳細頁面,也有這個按鈕。

1.1 問題

問題來了,我們發現,該按鈕在商品介紹上面,如果我們想放到下面,該怎麼做呢?

1.2 修改 Display 方法

protected override DriverResult Display(ProductPart part, string displayType, dynamic shapeHelper) {     //return ContentShape("Parts_Product", () => shapeHelper.Parts_Product(     //        Price: part.UnitPrice,     //        Sku: part.Sku     //    ));     return Combined(         // Shape 1: Parts_Product         ContentShape("Parts_Product", () => shapeHelper.Parts_Product(             Price: part.UnitPrice,             Sku: part.Sku         )),         // Shape 2: Parts_Product_AddButton         ContentShape("Parts_Product_AddButton", () => shapeHelper.Parts_Product_AddButton())         );

在修改後的方法内,我們創造了一個新的 Shape,叫做 Parts_Product_AddButton,同時,我們使用 Combined 方法,它傳回的是依舊是 DriverResult,隻不過,它組合了兩個形狀。

這個時候,我們知道,需要建立一個 Views/Parts/Product.Addbutton.cshtml 檔案:

<button>@T("Add to shoppingcart")</button>

當然,我們得把原先的 Product.cshtml 中的代碼給恢複過來。

然後,修改 placement.info,為:

<Placement>   <Place Parts_Product_Edit="Content:1" />   <Place Parts_Product="Content:0" />   <Place Parts_Product_AddButton="Content:after" /> </Placement>

然後,看到不一樣了:

Orchard子產品開發全接觸4:深度改造前台

二:實作 添加到購物車 功能

2.1 前台準備

首先,我們建立檔案夾 Controllers,然後控制器:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Mvc; namespace TMinji.Shop.Controllers     public class ShoppingCartController : Controller     {         [HttpPost]         public ActionResult Add(int id)         {             return RedirectToAction("Index");         }     }

然後,修改 Views/Parts/Product.AddButton.cshtml:,

@using (Html.BeginForm("Add", "ShoppingCart", new { id = -1 }))     <button type="submit">@T("Add to shoppingcart")</button>

讓它變成一個表單,并且指向到 Add 方法。

注意到,我們這裡傳遞的 id = -1,是以,我們還需要做一件事情,那就是把真是的商品 id 傳遞過來,才能添加商品。

于是乎,我們首先應該把 id 傳遞到 shape 中,修改,我們的 Display 方法,如下:

        ContentShape("Parts_Product_AddButton", () => shapeHelper.Parts_Product_AddButton(             ProductId: part.Id))

然後,前台 Views/Parts/Product.AddButton.cshtml 如下:

    var productId = (int)Model.ProductId; @using (Html.BeginForm("Add", "ShoppingCart", new { id = productId }))

現在,就可以把值傳遞到控制器了,現在,我們需要實作業務邏輯部分。

2.2 業務邏輯之 Orchard Service

在 Models 目錄下,增加 ShoppingCartItem 實體類:

[Serializable] public sealed class ShoppingCartItem     public int ProductId { get; private set; }     private int _quantity;     public int Quantity         get { return _quantity; }         set             if (value < 0)                 throw new IndexOutOfRangeException();             _quantity = value;     public ShoppingCartItem()     public ShoppingCartItem(int productId, int quantity = 1)         ProductId = productId;         Quantity = quantity;

建立 Services 檔案夾,然後建立 IShoppingCart 接口,

public interface IShoppingCart : IDependency IEnumerable<ShoppingCartItem> Items { get; } void Add(int productId, int quantity = 1); void Remove(int productId); ProductPart GetProduct(int productId); decimal Subtotal(); decimal Vat(); decimal Total(); int ItemCount(); void UpdateItems();

然後,其實作類:

using Orchard; using Orchard.ContentManagement; using System.Web; using TMinji.Shop.Models; namespace TMinji.Shop.Services     public class ShoppingCart : IShoppingCart         private readonly IWorkContextAccessor _workContextAccessor;         private readonly IContentManager _contentManager;         public IEnumerable<ShoppingCartItem> Items { get { return ItemsInternal.AsReadOnly(); } }         private HttpContextBase HttpContext             get { return _workContextAccessor.GetContext().HttpContext; }         private List<ShoppingCartItem> ItemsInternal             get             {                 var items = (List<ShoppingCartItem>)HttpContext.Session["ShoppingCart"];                 if (items == null)                 {                     items = new List<ShoppingCartItem>();                     HttpContext.Session["ShoppingCart"] = items;                 }                 return items;             }         public ShoppingCart(IWorkContextAccessor workContextAccessor, IContentManager contentManager)             _workContextAccessor = workContextAccessor;             _contentManager = contentManager;         public void Add(int productId, int quantity = 1)             var item = Items.SingleOrDefault(x => x.ProductId == productId);             if (item == null)                 item = new ShoppingCartItem(productId, quantity);                 ItemsInternal.Add(item);             else                 item.Quantity += quantity;         public void Remove(int productId)                 return;             ItemsInternal.Remove(item);         public ProductPart GetProduct(int productId)             return _contentManager.Get<ProductPart>(productId);         public void UpdateItems()             ItemsInternal.RemoveAll(x => x.Quantity == 0);         public decimal Subtotal()             return Items.Select(x => GetProduct(x.ProductId).UnitPrice * x.Quantity).Sum();         public decimal Vat()             return Subtotal() * .19m;         public decimal Total()             return Subtotal() + Vat();         public int ItemCount()             return Items.Sum(x => x.Quantity);         private void Clear()             ItemsInternal.Clear();             UpdateItems();

以上代碼不再一一解釋,相信大家能看明白,然後,相應的,修改控制器吧:

using Orchard.Mvc; using TMinji.Shop.Services;         private readonly IShoppingCart _shoppingCart;         private readonly IOrchardServices _services;         public ShoppingCartController(IShoppingCart shoppingCart, IOrchardServices services)             _shoppingCart = shoppingCart;             _services = services;             // Add the specified content id to the shopping cart with a quantity of 1.             _shoppingCart.Add(id, 1);             // Redirect the user to the Index action (yet to be created)         public ActionResult Index()             // Create a new shape using the "New" property of IOrchardServices.             var shape = _services.New.ShoppingCart();             // Return a ShapeResult             return new ShapeResult(this, shape);

在控制器中,我們看到了三點變化:

1:構造器接受了兩個對象,它們是被注入的,這會由 Orchard 完成;

2:Add 方法可以添加商品到購物車了;

3:增加了一個 Index 方法。可以看到在這個方法中,我們又建立了一個 Shape,而這個 Shape 的名字叫做 ShoppingCart。注意哦,它和背景建立 Shape 不一樣(記得嗎,在 Display 方法 中),這個 shape 對于那個的 cshtml 檔案為Views/ShoppingCart.cshtml:

TODO: display our shopping cart contents!

如果我們這個時候運作代碼,會發現點選 添加到購物車 後,變成 404 。這是因為,我們沒有為路由加上 area,它是什麼,是子產品名,Orchard 會根據這個 area,路由到對于的子產品中的 controller。故,我們應該修改Views/Parts/Product.AddButton.cshtml:

@using (Html.BeginForm("Add", "ShoppingCart", new { id = productId, area = "TMinji.Shop" }))

現在,繼續運作代碼,現在,我們得到錯誤:

The required anti-forgery form field "__RequestVerificationToken" is not present.

當然,這個錯誤,熟悉 MVC 的我們,已經知道怎麼修改了,修改之:

@using (Html.BeginFormAntiForgeryPost(Url.Action("Add", "ShoppingCart", new { id = productId, area = "TMinji.Shop" })))

再次運作:

Orchard子產品開發全接觸4:深度改造前台

我們看到,這個頁面沒有包含目前的 Theme 的母版頁,回到控制器,加一個 ThemedAttribute(當然,我們得 using Orchard.Themes;),如下:

[Themed] public ActionResult Index()     // Create a new shape using the "New" property of IOrchardServices.     var shape = _services.New.ShoppingCart();     // Return a ShapeResult     return new ShapeResult(this, shape);

這個時候,再次運作,得到了如下的理想效果:

Orchard子產品開發全接觸4:深度改造前台

總結

1:前台的展現,主要通過 MVC 的控制器來實作的,而背景則繞開了控制器;

2:業務邏輯,使用 Service 機制,而不是我們自己瞎寫的類和邏輯(當然,也可以),但 Service 機制看上去更 Orchard;

3:前背景建立 Shape 的方式是不一樣的。

本文轉自最課程陸敏技部落格園部落格,原文連結:http://www.cnblogs.com/luminji/p/3860188.html,如需轉載請自行聯系原作者