【ASP.NET Web API教程】2.3.7 創建首頁


注:本文是【ASP.NET Web API系列教程】的一部分,如果您是第一次看本博客文章,請先看前面的內容。

Part 7: Creating the Main Page
第7部分:創建首頁

本文引自:http://www.asp.net/web-api/overview/creating-web-apis/using-web-api-with-entity-framework/using-web-api-with-entity-framework,-part-7

Creating the Main Page
創建首頁

In this section, you will create the main application page. This page will be more complex than the Admin page, so we’ll approach it in several steps. Along the way, you'll see some more advanced Knockout.js techniques. Here is the basic layout of the page:
在這一小節中將創建主應用程序的首頁。這個頁面要比Admin頁面更復雜些。因此,我們將采用幾個步驟。在此過程中,你將看到一些更高級的Knockout.js技術。以下是此頁面的基本布局(見圖2-26):

WebAPI2-26

圖2-26. 首頁布局

  • "Products" holds an array of products.
    “產品”放置產品數組。
  • "Cart" holds an array of products with quantities. Clicking “Add to Cart” updates the cart.
    “購物車”放置帶有訂購數的產品數組。點擊“加入購物車”會對購物車進行更新。
  • "Orders" holds an array of order IDs.
    “訂單”放置訂單的ID數組(訂單號數組)。
  • "Details" holds an order detail, which is an array of items (products with quantities)
    “細節”放置一份訂單細節,這是一個條目數組(帶有訂購數的產品)。

We’ll start by defining some basic layout in HTML, with no data binding or script. Open the file Views/Home/Index.cshtml and replace all of the contents with the following:
我們將以無數據的綁定或腳本首先定義一些HTML的基本布局。打開Views/Home/Index.cshtml文件,並將全部內容替換如下:

<div class="content"> 
    <!-- List of products(產品列表) --> 
    <div class="float-left"> 
    <h1>Products</h1> 
    <ul id="products"> 
    </ul> 
    </div> 
    <!—Cart(購物車) --> 
    <div id="cart" class="float-right"> 
    <h1>Your Cart</h1> 
        <table class="details ui-widget-content"> 
    </table> 
    <input type="button" value="Create Order"/> 
    </div> 
</div> 
<div id="orders-area" class="content" > 
    <!-- List of orders --> 
    <div class="float-left"> 
    <h1>Your Orders</h1> 
    <ul id="orders"> 
    </ul> 
    </div> 
   <!-- Order Details(訂單細節) --> 
    <div id="order-details" class="float-right"> 
    <h2>Order #<span></span></h2> 
    <table class="details ui-widget-content"> 
    </table> 
    <p>Total: <span></span></p> 
    </div> 
</div>

Next, add a Scripts section and create an empty view-model:
下一步,添加一個腳本片段,並創建一個空的視圖模型:

@section Scripts { 
  <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.1.0.js")"></script> 
  <script type="text/javascript"> 
    function AppViewModel() { 
        var self = this; 
        self.loggedIn = @(Request.IsAuthenticated ? "true" : "false"); 
    } 
    $(document).ready(function () { 
        ko.applyBindings(new AppViewModel()); 
    }); 
  </script> 
}

Based on the design sketched earlier, our view model needs observables for products, cart, orders, and details. Add the following variables to the AppViewModel object:
基於前面的設計框架,我們的視圖需要產品、購物車、訂單以及訂單細節的可見對象(observables)。將以下變量添加到AppViewModel對象:

self.products = ko.observableArray(); 
self.cart = ko.observableArray(); 
self.orders = ko.observableArray(); 
self.details = ko.observable();

Users can add items from the products list into the cart, and remove items from the cart. To encapsulate these functions, we'll create another view-model class that represents a product. Add the following code to AppViewModel:
用戶可以把產品列表中的條目添加到購物車中,以及從購物車刪除條目。為了封裝這些函數,我們將創建另一個表示產品的視圖模型類。將以下代碼添加到AppViewModel

function AppViewModel() { 
    // ... 
    // NEW CODE 
    // 新代碼
    function ProductViewModel(root, product) { 
        var self = this; 
        self.ProductId = product.Id; 
        self.Name = product.Name; 
        self.Price = product.Price; 
        self.Quantity = ko.observable(0); 
        self.addItemToCart = function () { 
            var qty = self.Quantity(); 
            if (qty == 0) { 
                root.cart.push(self); 
            } 
            self.Quantity(qty + 1); 
        }; 
        self.removeAllFromCart = function () { 
            self.Quantity(0); 
            root.cart.remove(self); 
        }; 
    } 
}

The ProductViewModel class contains two functions that are used to move the product to and from the cart: addItemToCart adds one unit of the product to the cart, and removeAllFromCart removes all quantities of the product.
這個ProductViewModel類包含兩個函數,用於對購物車添加或刪除產品:addItemToCart將一個產品單位添加到購物車(即,產品訂購數加1 — 譯者注),而removeAllFromCart刪除產品的全部訂購數。

Users can select an existing order and get the order details. We'll encapsulate this functionality into another view-model:
用戶可以選擇一個已有訂單,並獲取該訂單細節。我們將把這個功能封裝到另一個視圖模型之中:

function AppViewModel() { 
    // ... 
    // NEW CODE 
    // 新代碼
    function OrderDetailsViewModel(order) { 
        var self = this; 
        self.items = ko.observableArray(); 
        self.Id = order.Id; 
        self.total = ko.computed(function () { 
            var sum = 0; 
            $.each(self.items(), function (index, item) { 
                sum += item.Price * item.Quantity; 
            }); 
            return '$' + sum.toFixed(2); 
        }); 
        $.getJSON("/api/orders/" + order.Id, function (order) { 
            $.each(order.Details, function (index, item) { 
                self.items.push(item); 
            }) 
        }); 
    }; 
}

The OrderDetailsViewModel is initialized with an order, and it fetches the order details by sending an AJAX request to the server.
OrderDetailsViewModel用一個訂單進行初始化,並能通過向服務器發送一個AJAX請求來捕捉該訂單的細節。

Also, notice the total property on the OrderDetailsViewModel. This property is a special kind of observable called a computed observable. As the name implies, a computed observable lets you data bind to a computed value—in this case, the total cost of the order.
另外,要注意到OrderDetailsViewModel上的total屬性。這個屬性是一個叫做“已計算可見對象”的特殊類型的可見對象。正如其名稱所暗示的那樣,一個已計算可見對象可以讓你把數據綁定到一個已計算的值 — 在此例中是訂單的總費用(total cost)。

Next, add these functions to AppViewModel:
接下來,把這些函數添加到AppViewModel

  • resetCart removes all items from the cart.
    resetCart刪除購物車的所有條目。
  • getDetails gets the details for an order (by pusing pushing a new OrderDetailsViewModel onto the details list).
    getDetails獲取一份訂單的細節(通過把一個新的OrderDetailsViewModel推入details列表)。
  • createOrder creates a new order and empties the cart.
    createOrder創建一個新的訂單,並清空購物車。
function AppViewModel() { 
    // ... 
    // NEW CODE
    // 新代碼
    self.resetCart = function() { 
        var items = self.cart.removeAll(); 
        $.each(items, function (index, product) { 
            product.Quantity(0); 
        }); 
    } 
    self.getDetails = function (order) { 
        self.details(new OrderDetailsViewModel(order)); 
    } 
    self.createOrder = function () { 
        var jqxhr = $.ajax({ 
            type: 'POST', 
            url: "api/orders", 
            contentType: 'application/json; charset=utf-8', 
            data: ko.toJSON({ Details: self.cart }), 
            dataType: "json", 
            success: function (newOrder) { 
                self.resetCart(); 
                self.orders.push(newOrder); 
            }, 
            error: function (jqXHR, textStatus, errorThrown) { 
                self.errorMessage(errorThrown); 
            }   
        }); 
    }; 
};

Finally, initialize the view model by making AJAX requests for the products and orders:
最后,通過發送對產品和訂單的AJAX請求的辦法,對這個視圖模型進行初始化:

function AppViewModel() { 
    // ... 
    // NEW CODE 
    // 新代碼
    // Initialize the view-model. 
    $.getJSON("/api/products", function (products) { 
        $.each(products, function (index, product) { 
            self.products.push(new ProductViewModel(self, product)); 
        }) 
    }); 
    $.getJSON("api/orders", self.orders); 
};

OK, that's a lot of code, but we built it up step-by-step, so hopefully the design is clear. Now we can add some Knockout.js bindings to the HTML.
好了,代碼很多,但我們一步步把它建立起來了,希望這一設計是清晰的。現在,我們可以對這個HTML添加一些Knockout.js綁定。

Products
產品

Here are the bindings for the product list:
以下是對產品列表的綁定:

<ul id="products" data-bind="foreach: products"> 
    <li> 
        <div> 
            <span data-bind="text: Name"></span>  
            <span class="price" data-bind="text: '$' + Price"></span> 
        </div> 
        <div data-bind="if: $parent.loggedIn"> 
            <button data-bind="click: addItemToCart">Add to Order</button> 
        </div> 
    </li> 
</ul>

This iterates over the products array and displays the name and price. The "Add to Order" button is visible only when the user is logged in.
它對產品數組進行了循環,並顯示名稱和價格。“加入購物車”按鈕只在用戶登錄時才是可見的。

The "Add to Order" button calls addItemToCart on the ProductViewModel instance for the product. This demonstrates a nice feature of Knockout.js: When a view-model contains other view-models, you can apply the bindings to the inner model. In this example, the bindings within the foreach are applied to each of the ProductViewModel instances. This approach is much cleaner than putting all of the functionality into a single view-model.
“加入購物車”按鈕針對(所選)產品調用ProductViewModel實例上的addItemToCart。這演示了Knockout.js的一個很好的特性:當一個視圖模型含有其它視圖模型時,你可以把綁定運用於內部模型。在這個例子中,在foreach中的綁定被運用於每個ProductViewModel實例。這種辦法要比把所有功能放在一個單一的視圖模型中要清晰得多。

Cart
購物車

Here are the bindings for the cart:
以下是對購物車的綁定:

<div id="cart" class="float-right" data-bind="visible: cart().length > 0"> 
<h1>Your Cart</h1> 
    <table class="details ui-widget-content"> 
    <thead> 
        <tr><td>Item</td><td>Price</td><td>Quantity</td><td></td></tr> 
    </thead>     
    <tbody data-bind="foreach: cart"> 
        <tr> 
            <td><span data-bind="text: $data.Name"></span></td> 
            <td>$<span data-bind="text: $data.Price"></span></td> 
            <td class="qty"><span data-bind="text: $data.Quantity()"></span></td> 
            <td><a href="#" data-bind="click: removeAllFromCart">Remove</a></td> 
        </tr> 
    </tbody> 
</table> 
<input type="button" data-bind="click: createOrder" value="Create Order"/>

This iterates over the cart array and displays the name, price, and quantity. Note that the "Remove" link and the "Create Order" button are bound to view-model functions.
這是對購物車的循環,並且顯示名稱、價格和數據。注意,“刪除”鏈接和“創建訂單”按鈕都被綁定到視圖模型的函數上。

Orders
訂單

Here are the bindings for the orders list:
以下是對訂單列表的綁定:

<h1>Your Orders</h1> 
<ul id="orders" data-bind="foreach: orders"> 
<li class="ui-widget-content"> 
    <a href="#" data-bind="click: $root.getDetails"> 
        Order # <span data-bind="text: $data.Id"></span></a> 
</li> 
</ul>

This iterates over the orders and shows the order ID. The click event on the link is bound to the getDetails function.
它對訂單進行了循環,並顯示訂單ID。鏈接上的點擊事件被綁定到getDetails函數。

Order Details
訂單細節

Here are the bindings for the order details:
以下是對訂單細節的綁定:

<div id="order-details" class="float-right" data-bind="if: details()"> 
<h2>Order #<span data-bind="text: details().Id"></span></h2> 
<table class="details ui-widget-content"> 
    <thead> 
        <tr><td>Item</td><td>Price</td><td>Quantity</td><td>Subtotal</td></tr> 
    </thead>     
    <tbody data-bind="foreach: details().items"> 
        <tr> 
            <td><span data-bind="text: $data.Product"></span></td> 
            <td><span data-bind="text: $data.Price"></span></td> 
            <td><span data-bind="text: $data.Quantity"></span></td> 
            <td> 
                <span data-bind="text: ($data.Price * $data.Quantity).toFixed(2)"></span> 
            </td> 
        </tr> 
    </tbody> 
</table> 
<p>Total: <span data-bind="text: details().total"></span></p> 
</div>

This iterates over the items in the order and displays the product, price, and quanity quantity. The surrounding div is visible only if the details array contains one or more items.
它對訂單中的條目進行循環,並顯示產品、價格和數量。div所包圍的部分只在訂單細節數組含有一個或多個條目時才會顯示。

Conclusion
結論

In this tutorial, you created an application that uses Entity Framework to communicate with the database, and ASP.NET Web API to provide a public-facing interface on top of the data layer. We use ASP.NET MVC 4 to render the HTML pages, and Knockout.js plus jQuery to provide dynamic interactions without page reloads.
在這個教程中,你創建了一個應用程序,它用實體框架與數據庫進行通信,並用ASP.NET Web API提供了一個建立在數據層之上的面向公眾的接口。我們使用了ASP.NET MVC 4來渲染HTML頁面,並用Knckout.js加jQuery來提供不必進行頁面重載的動態交互。

Additional resources:
其它資源:

看完此文如果覺得有所收獲,懇請給個推薦


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM