当前位置:首页 >> 网络编程

Jquery Datatables的使用详解

参考:

Datatables中文网

Datatables官网

 Datatables 是一款强大的Jquery表格处理插件,样式方面可以兼容bootstrap3/4、JqueryUi等,也有默认的样式可以选择。使用Datatables可以很灵活的从服务端通过ajax更新表格数据,实现排序、分页等功能。

一、安装

登录官网下载,可以看到有一个选择的表单让你自定义下载包的内容,可以选择样式、扩展组件、Jquery库等,这个可以根据自己的需求下载,也可以先只下载Default的就可以了。

在你的项目中使用 DataTables,只需要引入三个文件即可,jQuery库,一个DataTables的核心js文件和一个DataTables的css文件。有的时候还需要DataTables样式的一些资源。

Jquery Datatables的使用详解

二、数据的绑定

如何将数据显示到Datatables中呢,有三种方式:

1. Dom

如果在html中生命的table标签下,tbody中有已经编辑好的数据的话,会直接显示出来。

<table id="table_id_example" class="display">
 <thead>
  <tr>
  <th>Column 1</th>
  <th>Column 2</th>
  </tr>
 </thead>
 <tbody>
  <tr>
  <td>Row 1 Data 1</td>
  <td>Row 1 Data 2</td>
  </tr>
  <tr>

2. JavaScript

可以在js中定义好数据源,然后在DT初始化的时候,通过data选项为表格配置数据,数据源可以是数组、对象、实例三种形式。

(1)数组

var data = [
 [
  "Tiger Nixon",
  "System Architect",
  "Edinburgh",
  "5421",
  "2011/04/25",
  "$3,120"
 ],
 [
  "Garrett Winters",
  "Director",
  "Edinburgh",
  "8422",
  "2011/07/25",
  "$5,300"
 ]
 ];
 
 $('#example').DataTable( {
 data: data
 } );

(2)实例

 function Employee ( name, position, salary, office ) {
 this.name = name;
 this.position = position;
 this.salary = salary;
 this._office = office;
 
 this.office = function () {
  return this._office;
 }
 };
 
 $('#example').DataTable( {
 data: [
  new Employee( "Tiger Nixon", "System Architect", "$3,120", "Edinburgh" ),
  new Employee( "Garrett Winters", "Director", "$5,300", "Edinburgh" )
 ],
 columns: [
  { data: 'name' },
  { data: 'salary' },
  { data: 'office()' },
  { data: 'position' }
 ]
 } );

(3)对象

var data = [
 {
  "name": "Tiger Nixon",
  "position": "System Architect",
  "salary": "$3,120",
  "start_date": "2011/04/25",
  "office": "Edinburgh",
  "extn": "5421"
 },
 {
  "name": "Garrett Winters",
  "position": "Director",
  "salary": "$5,300",
  "start_date": "2011/07/25",
  "office": "Edinburgh",
  "extn": "8422"
 }
 ];
 //object可以如下初始化表格
 $('#example').DataTable( {
 data: data,
 //使用对象数组,一定要配置columns,告诉 DataTables 每列对应的属性
 //data 这里是固定不变的,name,position,salary,office 为你数据里对应的属性
 columns: [
  { data: 'name' },
  { data: 'position' },
  { data: 'salary' },
  { data: 'office' }
 ]
 } );

可以看到,在html中定义好一个id是example的table后,可以使用DT提供的选项进行初始化,data是数据,可以将要展示的数据对象放到data选项后,然后通过columns选项为每一列的属性进行定义,DT就会根据columns中定义的属性找到对象中的成员进行绑定,如果是数组的话,会按照数组中定义的数据依次绑定到每一列上进行展示。

3. Ajax

前两种数据源的处理模式都是客户端处理,显然这不能满足大多数时候对于表格的要求。还好DT提供了一种可以通过Ajax与后端服务交互的方法,可以直接将后端提供的数据直接展示到表格上,分页和排序也很方便。后面的篇幅会侧重说DT如何通过Ajax如何与服务端完成数据交互。

三、通过选项完成一个服务端处理模式的Datatables

datatables中大量的选项可以用来定制你的表格展现给用户。

举个例子

datatables的配置是通过设置你定义的选项来完成的,如下:

$('#example').DataTable( {
 paging: false
} );

通过设置paging选项,禁止表格分页(默认是打开的)

假设你要在表格里使用滚动,你需要加上scrollY选项:

$('#example').DataTable( {
 scrollY: 400
} );

当然你可以组合多个选项来初始化datatables,启动滚动条,禁用分页

$('#example').DataTable( {
 paging: false,
 scrollY: 400
} );

再比如在上面说到的data选项和columns选项都是一种初始化定制DT的方法。

可以看到,通过DataTable(object)函数可以进行DT的定制,object是一个对象,对象中的每个成员变量都应该是一个DT的选项。

因为我们在一个项目中可能会用到多个DT,那有些选项其实是通用的,举个例子如果A、B的表格都允许排序并且允许检索,正常会写成:

$('#a).DataTable( {
 searching: true,
 ordering: true
} );

$('#b).DataTable( {
 searching: true,
 ordering: true
} );

当使用的表格多了后,后续维护会非常的麻烦,所以可以将通用的选项提取出来,然后再通用选项的基础上定制每个DT。

function getCommonOptions()
{
 var options = new Object();
 options.searching = true;
 options.ordering = true;
 return options;
}


var aOptions = getCommonOptions();
aOptions.scrollY = true;
$('#a).DataTable(aOptions);

var bOptions = getCommonOptions();
bOptions .scrollY = false;
$('#b).DataTable(bOptions);

这样,A和B都支持了检索和排序,但是A支持垂直滚动,但是B不支持垂直滚动。

所以首先可以看下一个公用的通过Ajax获取后端数据的DT是如何配置的。

/**通用列表**/
function createCommonTableOptions() {
 var oTemp = new Object;
 // 是否允许检索
 oTemp.searching = true;
 // 是否允许排序
 oTemp.ordering = true;
 // 默认排序
 oTemp.order = [[1,'desc']];
 // 是否显示情报 就是"当前显示1/100记录"这个信息
 oTemp.info = true;
 // 是否允许翻页,设成false,翻页按钮不显示
 oTemp.paging = true;
 // 水平滚动条
 oTemp.scrollX = false;
 // 垂直滚动条
 oTemp.scrollY = true;
 // 是否可以选择每页展示的Item数量
 oTemp.lengthChange = true;
 // 选择每页展示数量的选项
 oTemp.lengthMenu = [10, 25, 50, 75, 100];
 // 每页展示数据条数默认值
 oTemp.pageLength = 10;
 //翻页按钮样式
 // numbers:数字
 // simple:前一页,后一页
 // simple_numbers:前一页,后一页,数字
 // full:第一页,前一页,后一页,最后页
 //full_numbers:第一页,前一页,后一页,最后页,数字
 //first_last_numbers:第一页,最后页,数字
 oTemp.pagingType = "simple_numbers";
 // 行样式应用 指定多个的话,第一行tr的class为strip1,第二行为strip2,第三行为strip3.
 // 第四行以后又开始从strip1循环。。。 如果想指定成斑马条状,这里的class必须指定为2个。
 oTemp.stripeClasses = ['line_1', 'line_2'];
 // 自动列宽
 oTemp.autoWidth = true;
 // 是否表示 "processing" 加载中的信息,这个信息可以修改
 oTemp.processing = true;
 // 每次创建是否销毁以前的DataTable,默认false
 oTemp.destroy = false;
 // 控制表格各种信息的表示位置(比较复杂) 默认:lfrtip
 // 具体参考:https://datatables.net/reference/option/dom
 oTemp.dom = "lrtip";
 // language 用来定义展示信息的内容,如加载中显示的提示、当前页显示多少条时的提示、翻页按钮上的文字等等
 oTemp.language = {
 "processing": "翻页中。。。。",
 // 当前页显示多少条
 "lengthMenu": "当前显示 _MENU_ 条记录",
 // _START_(当前页的第一条的序号) ,_END_(当前页的最后一条的序号),_TOTAL_(筛选后的总件数),
 // _MAX_(总件数),_PAGE_(当前页号),_PAGES_(总页数)
 "info": "当前第 _PAGE_ 页, 共 _PAGES_ 页, 共 _MAX_ 条数据",
 "infoEmpty": "0条数据",
 "infoFiltered": "",
 // 没有数据的显示(可选),如果没指定,会用zeroRecords的内容
 "emptyTable": "没有记录",
 // 筛选后,没有数据的表示信息,注意emptyTable优先级更高
 "zeroRecords": "没有符合条件的记录",
 // 千分位的符号,只对显示有效,默认就是"," 一般不要改写
 //"thousands": "'",
 // 小数点位的符号,对输入解析有影响,默认就是"." 一般不要改写
 //"decimal": "-",
 // 翻页按钮文字控制
 "paginate": {
  "first": "第一页",
  "last": "最后一页",
  "next": "上一页",
  "previous": "下一页"
 },
 "loadingRecords": "正在加载中,请稍后。。。"
 };
 // 默认是false
 // 如果设为true,将只渲染当前也的html,速度会很快,但是通过API就访问不到所有页的数据,有利有弊
 //"deferRender": false,
 // 服务器端处理方式
 oTemp.serverSide = true;
 return oTemp;
}

每行选项都加了注释,如果希望了解更详细,可以参考官方的用户手册。注意serverSide一定要设置为true。

一个项目中的多个表最大的不同是啥呢?首先,肯定是他们的列不同,如果列相同的话就成了相同的表格了。其次,因为列不同,所以需要绑定的数据以及数据的接口肯定也不同。

通过一个具体的例子看一下。我要实现一个功能,手机通过定时轮询的方法查看服务端向他发送的命令(比如让手机上报自己的定位、上传自己的通话记录等)。那这个服务端向手机发送的命令,我需要一个后台管理平台进行管理,其中一个表格就是要展示所有的命令,包括命令内容、创建时间和执行时间等。

首先看下官方给出的前端通过Ajax向后端服务传递的入参格式:

名称 类型 描述 draw integerJS

绘制计数器。这个是用来确保Ajax从服务器返回的是对应的(Ajax是异步的,因此返回的顺序是不确定的)。 要求在服务器接收到此参数后再返回(具体看 下面)

start integerJS

第一条数据的起始位置,比如0代表第一条数据

length integerJS

告诉服务器每页显示的条数,这个数字会等于返回的 data集合的记录数,可能会大于因为服务器可能没有那么多数据。这个也可能是-1,代表需要返回全部数据(尽管这个和服务器处理的理念有点违背)

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.dataOption 定义。

columns[i][name] stringJS

columns 的名字,由 columns.nameOption 定义。

columns[i][searchable] booleanJS

标记列是否能被搜索,为true代表可以,否则不可以,这个是由 columns.searchableOption 控制

columns[i][orderable] booleanJS

标记列是否能排序,为 true代表可以,否则不可以,这个是由 columns.orderableOption 控制

columns[i][search][value] stringJS

标记具体列的搜索条件

columns[i][search][regex] booleanJS

特定列的搜索条件是否视为正则表达式, 如果为 true代表搜索的值是作为正则表达式处理,为 false则不是。 注意:通常在服务器模式下对于大数据不执行这样的正则表达式,但这都是自己决定的

这个param是由DT自己生成的,我们也可以自己增加一些我们想添加的入参数据。先看一下这个DT自己生成的参数在调试过程中抓取的结构:

Jquery Datatables的使用详解 

感觉有点复杂,其实我们自己开发后端时候所需要的查询条件并没有那么复杂,所以在后端接受的时候可以简化一下

package com.springapp.mvc.params;

/**
 * Created by qinyy on 2018/8/14.
 */
public class OperationQueryParam
{
 private int draw;
 // 分页查询起始下标
 private int start;
 // 分页查询偏移量--- 既每页展示的数据数量
 private int offset;
 // 排序属性
 private String sortPro;
 // 排序方式 0 asc 1 desc
 private int sortType;

 public String getSortPro()
 {
 return sortPro;
 }

 public void setSortPro(String sortPro)
 {
 this.sortPro = sortPro;
 }

 public int getSortType()
 {
 return sortType;
 }

 public void setSortType(int sortType)
 {
 this.sortType = sortType;
 }

 public int getStart()
 {
 return start;
 }

 public void setStart(int start)
 {
 this.start = start;
 }

 public int getOffset()
 {
 return offset;
 }

 public void setOffset(int offset)
 {
 this.offset = offset;
 }

 public int getDraw() {
 return draw;
 }

 public void setDraw(int draw) {
 this.draw = draw;
 }
}

我只接受这些字段就好了,就可以完成查询了,draw这个字段其实就是一个标识,因为查询是异步的,所以需要在服务端查询好数据后把这个标识原封不动的返回给DT,使DT可以将请求和响应的处理对应起来。

我在服务端需要接受的东西有些是DT不会自动生成的,那么如何添加这些我们自己觉得有用的字段呢?一会儿说完出参格式的时候会把代码贴出来进行说明。

再看一下官方给出的出参的说明

名称 类型 描述 draw integerJS

必要。上面提到了,Datatables发送的draw是多少那么服务器就返回多少。 这里注意,作者出于安全的考虑,强烈要求把这个转换为整形,即数字后再返回,而不是纯粹的接受然后返回,这是 为了防止跨站脚本(XSS)攻击。

recordsTotal integerJS

必要。即没有过滤的记录数(数据库里总共记录数)

recordsFiltered integerJS

必要。过滤后的记录数(如果有接收到前台的过滤条件,则返回的是过滤后的记录数)

data arrayType

必要。表中中需要显示的数据。这是一个对象数组,也可以只是数组,区别在于 纯数组前台就不需要用 columns绑定数据,会自动按照顺序去显示 ,而对象数组则需要使用 columns绑定数据才能正常显示。 注意这个 data的名称可以由 ajaxOption ajax不定时一讲 的 ajax.dataSrcOption ajax.dataSrc 1不定时一讲 ajax.dataSrc 2不定时一讲 控制

error stringJS

可选。你可以定义一个错误来描述服务器出了问题后的友好提示

除了上面的返回参数以外你还可以加入下面的参数,来实现对表格数据的自动绑定

名称 类型 描述 DT_RowId stringJS

自动绑定到 tr节点上

DT_RowClass stringJS

自动把这个类名添加到 tr

DT_RowData objectJS

使用 jQuery.data() 方法把数据绑定到row中,方便之后用来检索(比如加入一个点击事件)

DT_RowAttr objectJS

自动绑定数据到 tr上,使用 jQuery.attr() 方法,对象的键用作属性,值用作属性的值。注意这个 需要 Datatables 1.10.5+的版本才支持

其实除了data这个字段以外,其他的信息都是交给DT自己控制的,比如说recordsTotal,我们在后端查询出所有记录的数量后,把这个值置好,那么DT收到后就会在这里显示出这个记录的数量。然后我们可以截取data这个列表,进行进一步的绑定处理。

Jquery Datatables的使用详解

看下服务端定义的出参的格式:

public class CommonDatatableBean
{
 private int draw;
 private int recordsTotal;
 private int recordsFiltered;
 private List<Object> data;

 public int getDraw()
 {
 return draw;
 }

 public void setDraw(int draw)
 {
 this.draw = draw;
 }

 public int getRecordsTotal()
 {
 return recordsTotal;
 }

 public void setRecordsTotal(int recordsTotal)
 {
 this.recordsTotal = recordsTotal;
 }

 public int getRecordsFiltered()
 {
 return recordsFiltered;
 }

 public void setRecordsFiltered(int recordsFiltered)
 {
 this.recordsFiltered = recordsFiltered;
 }

 public List<Object> getData()
 {
 return data;
 }

 public void setData(List<Object> data)
 {
 this.data = data;
 }
}

可以看到这是一个通用的格式,所有的表格数据都可以封装在这个对象中返回,区别就是data中Object类型不同而已。

入参和出参格式说完了,可以看一下DT如何设置ajax请求后端的数据

var operationTableOption = createCommonTableOptions();
 operationTableOption.ajax = {
 // url可以直接指定远程的json文件,或是MVC的请求地址 /Controller/Action
 url: "/operation/query",
 type: 'POST',
 // 异步调用
 async:true,
 // 传给服务器的数据,可以添加我们自己的查询参数
 data: function (param)
 {
  param.start = param.start;
  param.offset = param.length;
  switch (param.order[0].column)
  {
  case 1:
   param.sortPro = "createtime";
   break;
  case 2:
   param.sortPro = "excutetime";
   break;
  }

  if("asc" == param.order[0].dir)
  {
  param.sortType = 0;
  }
  else if("desc" == param.order[0].dir)
  {
  param.sortType = 1;
  }
  return param;
 },
 //用于处理服务器端返回的数据。 dataSrc是DataTable特有的
 dataFilter: function (myJson)
 {
  var result = JSON.parse(myJson);
  var retStr = JSON.stringify(result.data);
  return retStr;
 }
 };

首先,通过通用配置选项的函数获取了一个通用选项的对象operationTableOption,然后为operationTableOption设置ajax选项。

首先设置请求地址,因为ajax正常情况下是不能跨域的,所以直线后面的path就可以,然后指定请求类型为POST。设置为异步请求。定义一个拦截请求的方法设置到data属性中,这样就可以完成自己请求的定制了。

这个请求主要就是根据要排序列的序号,给服务端传递排序字段的名称以及排序方式,这样服务端就可以不用了解DT入参的数据格式,而根据接口文档开发就行了。

最后有个dataFilter属性,这里要定义一个方法拦截服务端给前端返回的json数据,将json中的data数据列表(上面说出参格式的时候提到过)给剥离出来并返回,这样一会儿定义列数据绑定的时候就可以直接使用这个列表了。

ajax选项定义完毕,下一步要定义列相关的选项,定义列可以使用 columns 和 columnDefs这两个选项都可以用来定义列,首先,这两个选项中都要放入一个Definition Object的数组,区别就是columns需要对所有的列进行定义,也就是说这个表的每一个列都要和选项中放的DeinitionObject的一个子元素对应行程映射,columnDefs可以使用target来指定某一个定义对象应用到某一列,或者某一个定义对象是全局生效的,而且允许对同一个列进行多次定义。

为了使定义更清晰、更好理解、更方便维护,我一般都是使用columns进行定义。

operationTableOption.columns = [
 { "data": "operationid","orderable": false },
 { "data": "createtime" ,
  "orderable": true,
  "render": function ( data, type, row, meta )
  {
  if(data > 0)
   return $.myTime.UnixToDate(data,true)
  else
   return ""
  }
 },
 { "data": "excutetime" ,
  "orderable": true,
  "render": function ( data, type, row, meta )
  {
  if(data > 0)
   return $.myTime.UnixToDate(data,true)
  else
   return ""
  }},
 { "data": "needuploadlocation","orderable": false,
  "render": function ( data, type, row, meta )
  {
  if(data)
  {
   return "是";
  }
  else
  {
   return "否";
  }
  }
 },
 { "data": "recordsbegindate","orderable": false },
 { "data": "recordsenddate" ,"orderable": false},
 { "data": "uploadsoundsids","orderable": false },
 {"render":function ( data, type, row, meta )
 {

  var operationId = row.operationid;
  return "<button type=\"button\"οnclick=\"deleteOperation("+ operationId +"," +meta.row+ ")\">删除</button>";
 }}
 ];

可以看到,将后端给前端返回的出参,使用属性名依次绑定到列上,orderatble是说明这一列是否支持排序。render可以定义一个function也可以定义成其他属性,是用来转换数据的,比如返回的时间是一个时间戳,但是我要现实的是一个fomat的时间,就可以在render中转换。还有最后一行,我想在最后一列添加一个删除按钮,那这个删除按钮就可在这里通过数据的唯一索引来动态生成。

看下官方对render中使用function定义的说明:

function render( data, type, row, meta )

Description:

If a function is given, it will be executed whenever DataTables needs to get the data for a cell in the column. Note that this function might be called multiple times, as DataTables will call it for the different data types that it needs - sorting, filtering and display.

Parameters:

Name Type Optional 1 data

Any

No

The data for the cell (based on columns.data)

2 type

string

No

The type call data requested. This is used for DataTables' orthogonal data support. This value will be one of:

  • filter: Get the value that DataTables should use for filtering on this cell.
  • display: The value to display in the table.
  • type: Value to use for type detection. This should normally match the sort value - see type detection plug-in documentation.
  • sort: Get the data to use for sorting on this cell - the value returned should typically be numeric or a string, but custom plug-ins can be used - see the plug-in documentation. Note that this value is sort for legacy reasons (rather than being order which would be more consistent with the rest of the API).
  • undefined: Get the original data for the cell (i.e. unmodified).
  • Custom value: It is possible for plug-ins such as Responsive (through its responsive.orthogonal option) and Buttons (buttons.exportData()) to request custom data types specified by the developer. This can be useful in cases where you want send certain data to a particular extension.

See also the cell().render() method which can be used to execute the given rendering method at any arbitrary time.

3 row

Any

No

The full data source for the row (not based on columns.data)

4 meta

object

No

Since 1.10.1: An object that contains additional information about the cell being requested. This object contains the following properties:

  • row - The row index for the requested cell. See row().index().
  • col - The column index for the requested cell. See column().index().
  • settings - The DataTables.Settings object for the table in question. This can be used to obtain an API instance if required.

对ajax和columns都设置好以后,就可以将整个选项对象绑定到DT中了

$("table.operation-table").DataTable(operationTableOption);

四、服务端支持

@ResponseBody
 @RequestMapping(method = RequestMethod.POST,value = "query")
 public BaseResult queryOperation(OperationQueryParam param)
 {
 if(param == null)
  return null;
 BaseResult result = new BaseResult();
 CommonDatatableBean tableBean = new CommonDatatableBean();
 tableBean.setDraw(param.getDraw());
 int totalAmount = mOperationService.getOperationCount();
 tableBean.setRecordsTotal(totalAmount);
 tableBean.setRecordsFiltered(totalAmount);
 int limit = param.getStart();
 List<Object> list = new ArrayList<Object>();
 String sortType = param.getSortType() == 0"ASC":"DESC";
 List<Operation> operations = mOperationService.queryOperationPaged(limit,param.getOffset(),param.getSortPro(),sortType);
 if(operations != null && operations.size() > 0)
 {
  for(Operation operation:operations)
  {
  list.add(operation);
  }
 }
 tableBean.setData(list);
 result.setData(tableBean);
 result.setResult(ResultCode.SUCCESS);
 return result;
 }

好了这篇文章就介绍到这了,更多内容可以查看以前发布的文章。