ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。
ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个通用的WEB应用程序框架和项目模板。
ABP的官方网站 : http://www.aspnetboilerplate.com
ABP在Github上的开源项目:https://github.com/aspnetboilerplate
1. 引言
之前的文章ABP入门系列之分页功能的实现讲解了如何进行分页展示,但其分页展示仅适用于前台web分页,在后台管理系统中并不适用。后台管理系统中的数据展示一般都是使用一些表格插件来完成的。这一节我们就使用BootstrapTable进行举例说明。
2. BootstrapTable
基于 Bootstrap 的 jQuery 表格插件,通过简单的设置,就可以拥有强大的单选、多选、排序、分页,以及编辑、导出、过滤(扩展)等等的功能。
Bootstrap table是一个开源的轻量级功能非常丰富的前端表格插件。从命名来看就知道该表格样式由Bootstrap接手了,我们就不必纠结于样式的调整了。想对其有详细了解,可参考官方文档。
废话不多说,下面我们就直接上手演练。
3. 实操演练
因为使用BootstrapTable进行分页,主要的难点在插件的配置上,所以这一次我们直接对主要代码进行讲解,源码请自行前往Github上查看。
3.1. 添加BackendTasksController控制器
控制器中主要定义了列表、创建、编辑相关Action。其中最重要的方法是进行数据绑定的Aciton GetAllTasks,代码如下:
[DontWrapResult] public JsonResult GetAllTasks(int limit, int offset, string sortfiled, string sortway, string search, string status) { var sort = !string.IsNullOrEmpty(sortfiled) ? string.Format("{0} {1}", sortfiled, sortway) : ""; TaskState currentState; if (!string.IsNullOrEmpty(status)) Enum.TryParse(status, true, out currentState); var filter = new GetTasksInput { SkipCount = offset, MaxResultCount = limit, Sorting = sort, Filter = search }; if (!string.IsNullOrEmpty(status)) if (Enum.TryParse(status, true, out currentState)) filter.State = currentState; var pagedTasks = _taskAppService.GetPagedTasks(filter); return Json(new { total = pagedTasks.TotalCount, rows = pagedTasks.Items }, JsonRequestBehavior.AllowGet); }
下面来一一讲解下参数:
limit:分页参数,指定每页最多显示多少行;
offset:分页参数,指定偏移量;
sortField:排序参数,排序字段;
sortWay:排序参数,排序方式(升序or降序);
search:过滤参数,指定过滤的任务名称;
status:过滤参数,指定过滤的任务状态
这里面要注意的是参数的命名和顺序必须和前端传参保持一致
细心的你可能发现Action使用了[DontWrapResult]特性进行修饰,这样返回的json结果就不会被Abp提供的AbpJsonResult包裹,了解AbpJsonResult可参考ABP入门系列之Json格式化。
3.2. 添加List.cshtml进行列表展示
List.cshtml中主要的代码为:
@using Abp.Web.Mvc.Extensions @{ ViewBag.Title = L("BackendTaskList"); ViewBag.ActiveMenu = "BackendTaskList"; //Matches with the menu name in SimpleTaskAppNavigationProvider to highlight the menu item } <!-- 加载bootstrap-tablel的样式 --> <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.11.0/bootstrap-table.min.css" rel="external nofollow" > @section scripts{ @Html.IncludeScript("~/Views/backendtasks/list.js"); <!-- 加载bootstrap-tablel的script脚本 --> <script src="http://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.11.0/bootstrap-table.min.js"></script> <!-- Latest compiled and minified Locales --> <script src="http://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.11.0/locale/bootstrap-table-zh-CN.min.js"></script> } <div class="row"> <div class="panel-body"> <!-- 过滤框 --> <div class="panel panel-default"> <div class="panel-heading">查询条件</div> <div class="panel-body"> <form id="formSearch" class="form-horizontal"> <div class="form-group" style="margin-top: 15px"> <label class="control-label col-sm-1" for="txt-filter">任务名称</label> <div class="col-sm-3"> <input type="text" class="form-control" id="txt-filter"> </div> <label class="control-label col-sm-1" for="txt-search-status">状态</label> <div class="col-sm-3"> @Html.DropDownList("TaskStateDropdownList", null, new {id = "txt-search-status", @class = "form-control "}) </div> <div class="col-sm-4" style="text-align: left;"> <button type="button" style="margin-left: 50px" id="btn-query" class="btn btn-primary">查询</button> </div> </div> </form> </div> </div> </div> <!-- bootstrap-tablel指定的工具栏 --> <div id="toolbar" class="btn-group"> <button id="btn-add" type="button" class="btn btn-primary"> <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增 </button> <button id="btn-edit" type="button" class="btn btn-success"> <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改 </button> <button id="btn-delete" type="button" class="btn btn-danger"> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>删除 </button> </div> <!--bootstrap-table表体--> <table id="tb-tasks"></table> </div> <!--通过初始加载页面的时候提前将创建任务模态框加载进来--> @Html.Partial("_CreateTask") <!--编辑任务模态框通过ajax动态填充到此div中--> <div id="edit"> </div>
由于是demo性质,我直接使用的CDN来加载bootstrap table相关的css,js。
其中首先定义了过滤框,然后定义了bootstrap table专用的工具栏,其会在后续bootstrap table初始化指定。
接着使用<table id="tb-tasks"></table>
来定义bootstrap-table表体。
3.3. 添加list.js初始化bootstrap table
初始化就是为bootstrap table指定数据来源进行数据绑定、列名定义、排序字段、分页,事件绑定等。
我们新建一个list.js来进行初始化:
$(function() { //1.初始化Table var oTable = new TableInit(); oTable.Init(); //2.初始化Button的点击事件 var oButtonInit = new ButtonInit(); oButtonInit.Init(); }); var taskService = abp.services.app.task; var $table = $('#tb-tasks'); var TableInit = function() { var oTableInit = new Object(); //初始化Table oTableInit.Init = function() { $table.bootstrapTable({ url: '/BackendTasks/GetAllTasks', //请求后台的URL(*) method: 'get', //请求方式(*) toolbar: '#toolbar', //工具按钮用哪个容器 striped: true, //是否显示行间隔色 cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*) pagination: true, //是否显示分页(*) sortable: true, //是否启用排序 sortOrder: "asc", //排序方式 queryParams: oTableInit.queryParams, //传递参数(*) sidePagination: "server", //分页方式:client客户端分页,server服务端分页(*) pageNumber: 1, //初始化加载第一页,默认第一页 pageSize: 5, //每页的记录行数(*) pageList: [10, 25, 50, 100], //可供选择的每页的行数(*) search: false, //是否显示表格搜索,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大 strictSearch: true, showColumns: true, //是否显示所有的列 showRefresh: true, //是否显示刷新按钮 minimumCountColumns: 2, //最少允许的列数 clickToSelect: true, //是否启用点击选中行 height: 500, //行高,如果没有设置height属性,表格自动根据记录条数觉得表格高度 uniqueId: "Id", //每一行的唯一标识,一般为主键列 showToggle: true, //是否显示详细视图和列表视图的切换按钮 cardView: false, //是否显示详细视图 detailView: false, //是否显示父子表 columns: [ { radio: true }, { field: 'Title', title: '任务名称', sortable: true }, { field: 'Description', title: '任务描述' }, { field: 'AssignedPersonName', title: '任务分配' }, { field: 'State', title: '任务状态', formatter: showState }, { field: 'CreationTime', title: '创建日期', formatter: showDate }, { field: 'operate', title: '操作', align: 'center', valign: 'middle', clickToSelect: false, formatter: operateFormatter, events: operateEvents } ] }); };
这段JS中bootstrap table初始化配置的参数说明已经在代码中进行了注释。
下面对几个重要的参数进行讲解:
3.3.1. queryParams查询参数
初始化的时候我们指定了查询参数为:
queryParams: oTableInit.queryParams, //传递参数(*)
其中queryParams函数定义如下:
//指定bootstrap-table查询参数 oTableInit.queryParams = function(params) { var temp = { //这里的键的名字和控制器的变量名必须一直,这边改动,控制器也需要改成一样的 limit: params.limit, //页面大小 offset: params.offset, //页码 sortfiled: params.sort, //排序字段 sortway: params.order, //升序降序 search: $("#txt-filter").val(), //自定义传参-任务名称 status: $("#txt-search-status").val() //自定义传参-任务状态 }; return temp; };
和控制器中的Action的函数命名进行比较public JsonResult GetAllTasks(int limit, int offset, string sortfiled, string sortway, string search, string status)
,其中参数命名的大小写以及顺序与js中定义的查询参数保持一致,这也是必须要注意的一点。
3.3.2. 数据绑定
数据绑定包括以下三个部分:
url:就是用来指定请求后台的URL;
uniqueid:用来绑定每一行的唯一标识列,一般为主键列
columns:用来绑定每一列要显示的数据。
针对columns参数,其中field必须与你请求返回的json数据的key大小写保持一致;
title就是显示的列名;
align指定列的水平对其方式;
valign指定列的垂直对齐方式;
formatter用来指定列如何进行格式化输出,如操作列中指定formatter: operateFormatter,用来显示统一格式的操作组;
//指定操作组 function operateFormatter(value, row, index) { return [ '<a class="like" href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="Like">', '<i class="glyphicon glyphicon-heart"></i>', '</a>', ' <a class="edit" href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="Edit">', '<i class="glyphicon glyphicon-edit"></i>', '</a>', ' <a class="remove" href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="Remove">', '<i class="glyphicon glyphicon-remove"></i>', '</a>' ].join(''); }
events用来指定列的事件,比如操作列中指定events: operateEvents来指定每个操作对应的事件处理:
//指定table表体操作事件 window.operateEvents = { 'click .like': function(e, value, row, index) { alert('You click like icon, row: ' + JSON.stringify(row)); console.log(value, row, index); }, 'click .edit': function(e, value, row, index) { editTask(row.Id); }, 'click .remove': function(e, value, row, index) { deleteTask(row.Id); } };
3.3.3. 工具栏事件绑定
工具栏是我们在List.cshtml定义的新增、编辑、删除三个按钮,表格初始化时,直接为toolbar参数指定工具栏对应的id即可,如本例toolba: '#toolbar'。那工具栏按钮的事件在哪绑定呢?直接上代码吧:
//bootstrap-table工具栏按钮事件初始化 var ButtonInit = function() { var oInit = new Object(); var postdata = {}; oInit.Init = function() { //初始化页面上面的按钮事件 $("#btn-add") .click(function() { $("#add").modal("show"); }); $("#btn-edit") .click(function() { var selectedRaido = $table.bootstrapTable('getSelections'); if (selectedRaido.length === 0) { abp.notify.warn("请先选择要编辑的行!"); } else { editTask(selectedRaido[0].Id); } }); $("#btn-delete") .click(function() { var selectedRaido = $table.bootstrapTable('getSelections'); if (selectedRaido.length === 0) { abp.notify.warn("请先选择要删除的行!"); } else { deleteTask(selectedRaido[0].Id); } }); $("#btn-query") .click(function() { $table.bootstrapTable('refresh'); }); }; return oInit; };
该方法会在页面加载初被调用:
var oButtonInit = new ButtonInit(); oButtonInit.Init();
另外函数中使用了bootstrap table预置的2个比较实用的函数:
$table.bootstrapTable('getSelections'):获取表格选择项 $table.bootstrapTable('refresh'):刷新表格
4. 总结
本文主要讲解了如何使用bootstrap table进行后台分页的一般用法,讲解了bootstrap table参数的配置和几个注意事项。其中有很多功能并未讲到,具体请自行查询文档。