推荐使用 Razor Pages在 [ASP.NET](http://ASP.NET) Core MVC 框架中创建 UI。 首先,在ProductManagement.Web项目的*Pages*文件夹下创建一个*Products文件夹。然后,右键单击Products*文件夹,然后选择**Add**|**Razor Page**。选择**Razor 页面 - 空**选项,命名为`Index.cshtml`。下图显示了我们添加的页面的位置: ![](https://img.kancloud.cn/0b/9c/0b9cdf6d82f11488ef17deed37933671_211x218.png) 编辑内容,`Index.cshtml`如下代码块所示: ``` @page @using ProductManagement.Web.Pages.Products @model IndexModel <h1>Products Page</h1> ``` 在这里,我放置一个`h1`元素作为页眉。接下来我们在主菜单中添加一个菜单来打开这个页面。 ## 添加菜单项 ABP 提供了一个动态、模块化的菜单系统。每个模块都可以添加到主菜单。 打开*ProductManagement.Web项目的\*\*Menus*文件夹中的`ProductManagementMenuContributor`类,并在`ConfigureMainMenuAsync`方法末尾添加以下代码: ``` context.Menu.AddItem(     new ApplicationMenuItem(         "ProductManagement",         l["Menu:ProductManagement"],         icon: "fas fa-shopping-cart"             ).AddItem(         new ApplicationMenuItem(             "ProductManagement.Products",             l["Menu:Products"],             url: "/Products"         )     ) ); ``` 此代码添加了一个*产品管理*主菜单,其中包含产品菜单项。里面的`l["…"]`语法是用来获取本地化的值。 打开ProductManagement.Domain.Shared 项目的Localization/ProductManagement文件夹中的`en.json`文件,并将以下代码添加到该`texts`部分的末尾: ``` "Menu:ProductManagement": "Product Management", "Menu:Products": "Products" ``` 我们可以使用任意字符串值作为本地化键。在本例中,我们使用`Menu:`作为菜单的本地化键的前缀,例如`Menu:Products` 。我们将在\[*第 8 章*\] *使用 ABP 的功能和服务*中探讨本地化主题。 现在,重新运行,使用新的*产品管理*菜单打开*产品*页面,如图所示: ![](https://img.kancloud.cn/69/41/6941d4392e91905b9edc316f3abe43fd_788x190.png) ## 创建产品数据表 接下来我们将创建一个数据表显示带有分页和排序的产品列表。ABP 启动模板带有预安装和配置的JS 库 [**Datatables.net**](http://Datatables.net),用于显示表格数据。 打开`Index.cshtml`页面(在*Pages/Products*文件夹),并将其内容更改为以下内容: ``` @page @using ProductManagement.Web.Pages.Products @using Microsoft.Extensions.Localization @using ProductManagement.Localization @model IndexModel @inject IStringLocalizer<ProductManagementResource> L @section scripts {     <abp-script src="/Pages/Products/Index.cshtml.js" /> } <abp-card>     <abp-card-header>         <h2>@L["Menu:Products"]</h2>     </abp-card-header>     <abp-card-body>         <abp-table id="ProductsTable" striped-rows="true" />     </abp-card-body> </abp-card> ``` `abp-script`是一个 ABP 标签助手,用于将脚本文件添加到页面,并具有自动捆绑、压缩和版本控制功能。`abp-card`是另一个标签助手,以一种类型安全且简单的方式渲染 Card 组件。 > 我们可以使用标准的 HTML 标签。但是,ABP 标签助手极大地简化了 MVC/Razor 页面中的 UI 创建。此外,它们支持智能感知和编译时错误类型检查。我们将在\[*第 12 章*\] *使用 MVC/Razor 页面*中研究标签助手。 *在Pages/Products*文件夹下创建一个新的 JavaScript 文件,命名为`Index.cshtml.js`,内容如下: ``` $(function () {     var l = abp.localization.getResource('ProductManagement');     var dataTable = $('#ProductsTable').DataTable(         abp.libs.datatables.normalizeConfiguration({             serverSide: true,             paging: true,             order: [[0, "asc"]],             searching: false,             scrollX: true,             ajax: abp.libs.datatables.createAjax(                 productManagement.products.product.getList),             columnDefs: [                 /* TODO: Column definitions */             ]         })     ); }); ``` ABP 简化了数据表配置并提供了内置集成: * `abp.localization.getResource` 返回一个本地化对象,ABP 允许您在 JS中重用服务器端定义的本地化。 * `abp.libs.datatables.normalizeConfiguration`是 ABP 框架定义的辅助函数。它通过为缺失选项提供常规默认值来简化数据表的配置。 * `abp.libs.datatables.createAjax` 使 ABP 的动态 JS 客户端代理来适配数据表的参数格式。 * `productManagement.products.product.getList`是动态JS代理方法。 `columnDefs`数组用于定义数据表中的列: ``` {     title: l('Name'),     data: "name" }, {     title: l('CategoryName'),     data: "categoryName",     orderable: false }, {     title: l('Price'),     data: "price" }, {     title: l('StockState'),     data: "stockState",     render: function (data) {         return l('Enum:StockState:' + data);     } }, {     title: l('CreationTime'),     data: "creationTime",     dataFormat: 'date' } ``` 通常,列有一个`title`字段和一个`data`字段。`data`字段匹配`ProductDto`类中的属性名称,格式为**驼峰**式(一种命名风格,其中每个单词的第一个字母大写,第一个单词除外;它是JavaScript 语言中常用的命名风格)。 该`render`选项用于精细控制如何显示列数据。 在此页面上,我们使用了一些本地化键。我们应该先在本地化资源中定义它们。打开ProductManagement.Domain.Shared项目的*Localization/ProductManagement* *文件*夹中的`en.json`文件,并在该部分的末尾添加以下条目`texts`: ``` "Name": "Name", "CategoryName": "Category name", "Price": "Price", "StockState": "Stock state", "Enum:StockState:0": "Pre-order", "Enum:StockState:1": "In stock", "Enum:StockState:2": "Not available", "Enum:StockState:3": "Stopped", "CreationTime": "Creation time" ``` 看一下实际的产品数据表: ![](https://img.kancloud.cn/73/d7/73d79fe9b7564cb97196ac20d2983e92_949x445.png) 至此,我们创建了一个完整的工作页面,列出了支持分页和排序的产品。在接下来的部分中,我们将添加创建、编辑和删除产品的功能。