前言
最近使用ABP(ASP.NET Boilerplate)做新項目,以前都是自己擴展一個HtmlHelper來完成同步/異步分頁,但是有個地方一直不滿意,排序太費勁。
以前接觸過一點點的Datatables,知道它的排序非常方便,點擊表頭即可排序,還支持多列排序,然后就把Datatables集成到項目里了。
Datatables簡介
Datatables(以下簡稱dt)是一款jquery表格插件。它是一個高度靈活的工具,可以將任何HTML表格添加高級的交互功能。 點擊進入Datatables中文網
- 分頁,即時搜索和排序
- 幾乎支持任何數據源:DOM, javascript, Ajax 和 服務器處理
- 支持不同主題 DataTables, jQuery UI, Bootstrap, Foundation
- 各式各樣的擴展: Editor, TableTools, FixedColumns ……
- 豐富多樣的option和強大的API
- 支持國際化
- 超過2900+個單元測試
- 免費開源 ( MIT license )!
- 更多特性請到Datatables中文網查看看
與Asp.Net Mvc(以下簡稱mvc)結合使用
本文重點講解dt在mvc(此處應該吐槽webform)中的使用。其他語言也是差不多的用法。
初始化Datatables
引入js和css
//bootstrap的css
<link href="~/Content/bootstrap.min.css" rel="stylesheet"/>
//這里我們使用bootstrap的主題,其他的請對號入座
<link href="~/Scripts/DataTables-1.10.10/media/css/dataTables.bootstrap.min.css" rel="stylesheet" />
//jquery
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
//bootstrap主題的js
<script src="~/Scripts/DataTables-1.10.10/media/js/jquery.dataTables.min.js"></script>
//核心js
<script src="~/Scripts/DataTables-1.10.10/media/js/dataTables.bootstrap.js"></script>
//自定義的js,修改dt默認的一些配置(如中文提示)
<script src="~/Scripts/DataTables.js"></script>
//DataTables.js 這是Datatables的相關知識,具體作用請求官網查看
$.extend($.fn.dataTable.defaults, {
"dom": "<'row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-12 text-center'i>>" +
"<'row'<'col-sm-5'l><'col-sm-7'p>>",//默認是lfrtip
"processing": true,//加載中
"serverSide": true,//服務器模式(★★★★★重要,本文主要介紹服務器模式)
"searching": false,//datatables自帶的搜索
"scrollX": true,//X滑動條
"pagingType": "full_numbers",//分頁模式
"ajax": {
"type": "POST",//(★★★★★重要)
"contentType": "application/json; charset=utf-8"
},
"language": {
"processing": "加載中...",
"lengthMenu": "每頁顯示 _MENU_ 條數據",
"zeroRecords": "沒有匹配結果",
"info": "顯示第 _START_ 至 _END_ 項結果,共 _TOTAL_ 項",
"infoEmpty": "顯示第 0 至 0 項結果,共 0 項",
"infoFiltered": "(由 _MAX_ 項結果過濾)",
"infoPostFix": "",
"search": "搜索:",
"url": "",
"emptyTable": "沒有匹配結果",
"loadingRecords": "載入中...",
"thousands": ",",
"paginate": {
"first": "首頁",
"previous": "上一頁",
"next": "下一頁",
"last": "末頁"
},
"aria": {
"sortAscending": ": 以升序排列此列",
"sortDescending": ": 以降序排列此列"
}
}
});
初始化dt
dt支持多種數據源,在此我們只說“服務器處理”。
服務器處理的代碼如下(有些默認配置已經在上面的DataTables.js中配置,如開啟服務器模式"serverSide": true):
<table id="area" class="table" data-order="[[0,"desc"]]" width="100%">
<thead>
<tr>
<th data-data="Id" data-visible="false">Id</th>
<th data-data="Name">名稱</th>
<th data-data="Description" data-orderable="false">描述</th>
<th data-data="PointX">X坐標</th>
<th data-data="PointY">Y坐標</th>
</tr>
</thead>
</table>
<script>
$(function(){
var userTable = $('#area').DataTable({
"ajax": {
"url": "@Url.Action("GetDatas")",
"data": function(data) {
data.Name = $("#name").val();;//此處是添加額外的請求參數
return JSON.stringify(data);
}
}
});
});
</script>
dataTable和DataTable的區別
1.10.x版本后,有兩種初始化的寫法, $().dataTable() 返回的是一個jQuery實例, $().DataTable() 返回的是Datatables的api實例, 如果在使用過程中出現某某方法不存在不支持之類的,一般都是由於是用第一種方法初始化dt,用返回的對象去調用api的方法,所以報錯誤。
dt的api實例和jquery可以互轉 ,jquery轉api:dt.api();api轉jquery:dt.to$(); 詳細參考 api手冊
服務器端獲取Datatables的請求參數
當使用服務器處理時,dt會發送如下數據給服務器
| 名稱 | 類型 | 描述 |
|---|---|---|
| draw | integerJS | 請求次數計數器,每次發送給服務器后又原封返回. |
| start | integerJS | 第一條數據的起始位置,比如0代表第一條數據 |
| length | integerJS | 每頁顯示的條數. |
| search[value] | stringJS | 全局的搜索條件,針對於每一列( searchable需要設置為 true ) |
| search[regex] | booleanJS | 如果為 true代表全局搜索的值是作為正則表達式處理,為 false則不是。 |
| order[i][column] | integerJS | i是一個數組索引,對應的是 columns,從0開始,次參數表示那一列需要排序 |
| order[i][dir] | stringJS | 上面確定了是那一列,這個確定對應的列是什么樣的排序方式 desc 是降序 asc升序 |
| columns[i][data] | stringJS | columns 綁定的數據源,由 columns.data 定義 |
| columns[i][name] | stringJS | columns.name 里定義的名稱 |
| columns[i][searchable] | booleanJS | 標記列是否能被搜索 為 true代表可以,否則不可以,這個是由 columns.searchable 控制 |
| columns[i][orderable] | booleanJS | 標記列是否能排序 為 true代表可以,否則不可以,這個是由 columns.orderabl 控制 |
| columns[i][search][value] | stringJS | 特定列的搜索條件 |
| columns[i][search][regex] | booleanJS | 特定列的搜索條件是否視為正則表達式 |
可以看到,請求的參數還是很規則的。
我們可以使用Request.Form(post方式),Request.QueryString(get方式)或者Request.Params/Request獲取請求參數,但是如果這么做就太low了,每個方法都要寫一大堆的Request那還不如不用呢。
幸好,我們有ModelBinder。
使用asp.net mvc的ModelBinder(模型綁定)自定綁定請求的參數
上文講到如果使用Request的方式我們還不如不用,那么我們這里就用到了ModelBinder(其實也是對Request進行了封裝),我們可以用一個類還接收所有的請求參數,如下所示:
public JsonResult GetDatas(DataTablesParameters query)
{
}
下面我們開始編寫這個類。
此處的排序只實現了單列排序,如需多列排序請自行修改
/// <summary>
/// DataTables參數
/// </summary>
public class DataTablesParameters
{
/// <summary>
/// 請求次數計數器
/// </summary>
public int Draw { get; set; }
/// <summary>
/// 第一條數據的起始位置
/// </summary>
public int Start { get; set; }
/// <summary>
/// 每頁顯示的數據條數
/// </summary>
public int Length { get; set; }
/// <summary>
/// 數據列
/// </summary>
public List<DataTablesColumns> Columns { get; set; }
/// <summary>
/// 排序
/// </summary>
public List<DataTablesOrder> Order { get; set; }
/// <summary>
/// 搜索
/// </summary>
public DataTablesSearch Search { get; set; }
/// <summary>
/// 排序字段
/// </summary>
public string OrderBy
{
get
{
return Columns != null && Columns.Any() && Order != null && Order.Any()
? Columns[Order[0].Column].Data
: string.Empty;
}
}
/// <summary>
/// 排序模式
/// </summary>
public DataTablesOrderDir OrderDir
{
get
{
return Order != null && Order.Any()
? Order[0].Dir
: DataTablesOrderDir.Desc;
}
}
}
/// <summary>
/// 排序
/// </summary>
public class DataTablesOrder
{
/// <summary>
/// 排序的列的索引
/// </summary>
public int Column { get; set; }
/// <summary>
/// 排序模式
/// </summary>
public DataTablesOrderDir Dir { get; set; }
}
/// <summary>
/// 排序模式
/// </summary>
public enum DataTablesOrderDir
{
/// <summary>
/// 正序
/// </summary>
Asc,
/// <summary>
/// 倒序
/// </summary>
Desc
}
/// <summary>
/// 數據列
/// </summary>
public class DataTablesColumns
{
/// <summary>
/// 數據源
/// </summary>
public string Data { get; set; }
/// <summary>
/// 名稱
/// </summary>
public string Name { get; set; }
/// <summary>
/// 是否可以被搜索
/// </summary>
public bool Searchable { get; set; }
/// <summary>
/// 是否可以排序
/// </summary>
public bool Orderable { get; set; }
/// <summary>
/// 搜索
/// </summary>
public DataTablesSearch Search { get; set; }
}
/// <summary>
/// 搜索
/// </summary>
public class DataTablesSearch
{
/// <summary>
/// 全局的搜索條件的值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 是否為正則表達式處理
/// </summary>
public bool Regex { get; set; }
}
完成,這樣,當我們要使用Datatables的時候,我們使用這個類(或這個類的派生類)來接收請求參數。
返回Datatables規定的Json
Datatables要求返回的數據Json
| 名稱 | 類型 | 描述 |
|---|---|---|
| draw | integerJS | 請求次數計數器,每次發送給服務器后又原封返回. |
| recordsTotal | integerJS | 即沒有過濾的記錄數(數據庫里總共記錄數) |
| recordsFiltered | integerJS | 過濾后的記錄數 |
| data | arrayJS | 表中中需要顯示的數據。 |
| error | stringJS | 可選。你可以定義一個錯誤來描述服務器出了問題后的友好提示 |
處理返回的數據
當我們把包含第n頁的m數據放在一個List的時候,我們就需要封裝以下Datatables想要的數據格式了。
public class DataTablesResult<TEntity>
{
public DataTablesResult(int drawParam, int recordsTotalParam, int recordsFilteredParam, IReadOnlyList<TEntity> dataParam)
{
draw = drawParam;
recordsTotal = recordsTotalParam;
recordsFiltered = recordsFilteredParam;
data = dataParam;
}
public DataTablesResult(string errorParam)
{
error = errorParam;
}
public int draw { get; set; }
public int recordsTotal { get; set; }
public int recordsFiltered { get; set; }
public IReadOnlyList<TEntity> data { get; set; }
public string error { get; set; }
調用
var data = new Area().GetData();
if (!string.IsNullOrEmpty(query.Name))
data = data.Where(n => n.Name.Contains(query.Name));
data = data.OrderBy(n=>n.Id);
var count = data.Count();
var result = data.Skip(query.Start).Take(query.Length).ToList();
var resultJson = new DataTablesResult<Area>(draw, recordsFiltered, recordsFiltered, result);
return Json(resultJson);
渲染Table,展示數據
服務器已經返回了我們想要的Json數據,這時候我們就要開始渲染Table,讓它將數據顯示正常了。
dt的渲染方式主要有js渲染和html的data-屬性來渲染,我選擇使用data-屬性來渲染(即初始化的時候的table)。
Table的data-data屬性要和返回的實體類的屬性對應,否則渲染不上
添加行操作
我們需要在每行的后面加上諸如“修改”,“審核”,“刪除”等等的操作按鈕,在dt里怎么操作呢?
其實很簡單。
table的表頭最后一行加如下代碼:
<th data-orderable="false">操作</th>
在dt初始化的時候添加如下代碼:
"columnDefs": [
{
"targets": -1,//-1表示最后一行
"width": "100px",
render: function (data, type, full, meta) {
return '<a class="btn btn-sm btn-info" href="javascript:;">設置<i class="fa fa-cogs"></i></a> ' +
'<a class="btn btn-sm btn-info" href="javascript:;">刪除<i class="fa fa-trash"></i></a>';
}
}]
效果圖

源碼
具體位置在項目MvcDemo的Controller里
