Datatables是一款很便捷,功能很强大的前端分页插件。但是,在实际应用中,表格通常数据量会非常庞大,所以不提倡把数据一次性加载到页面。所以,datatables使用后台分页是一个不错的选择。但是,使用后台分页就要放弃datatables自带的3个功能:排序,分页条数选项,内容搜索。因为采用后端分页后,这三项内容都必须由后端完成(目前因为本人能力有限,只完成了分页和内容搜索,排序网上也有其他人做过,有心人不妨试成功了跟我说一下)。

       本人用过amazeui的datatables插件,也使用过原生datatables及其提供的bootstrap风格。两者其实一样。只是amazeui的datatables帮你汉化完和引入了amazeui的table风格。这里不再详述要引用的css和js,具体可以百度。

       首先讲讲如何使用datatables的汉化。

$('#dimtable').DataTable({
	    "searching" : false,//关闭自带搜索
		"bLengthChange" : false,//关闭自带分页选项
		"ordering" : false,//关闭排序
		"serverSide" : true,//这个用来指明是通过服务端来取数据
		"processing" : true, //打开数据加载时的等待效果  
		"oLanguage" : {
			"sLengthMenu" : "每页显示 _Menu_条记录",
			"sInfo" : "当前显示_START_到_END_条,共_TOTAL_条记录",
			"sInfoEmpty" : "显示第 0 至 0 项结果,共 0 项",
			"sZeroRecords" : "对不起,查询不到相关的数据",
			"sInfoFiltered" : "",//"(从 _MAX_ 条记录过滤)"此项为显示过滤信息
			"oPaginate" : {
				"sFirst" : "首页",
				"sPrevious" : "上一页",
				"sNext" : "下一页",
				"sLast" : "尾页"
			},
			"sSearch" : "查找"},
		});
});

       你需要定义一个table,及其表头。同时,可以通过控制th的宽度控制表格宽度。接下来,我们通过id给这个table绑定datatables。

<table width="100%" class="am-table am-table-compact am-table-striped tpl-table-black" id="list">
	<thead>
		<tr>
		  <th style="display:none">ID</th>
		  <th style="width:50%">地址</th>
		  <th style="width:20%">坐标</th>
		  <th style="width:30%">操作</th>
		</tr>
	</thead>
	<tbody>
	<!-- more data -->
	</tbody>
</table>

       接下来,我们开始第一种后台分页的方法。这种方法目前暂不支持自定义刷新,仅点击分页信息时会向后台请求数据。具体实现如下代码。

var datatable
$(function(){ 
	datatable=$('#list').DataTable({
		"searching": false,
		"bLengthChange": false,
		"ordering": false,
		"serverSide": true,//这个用来指明是通过服务端来取数据
        "sAjaxSource": "#(ctx)/admin/getHouseInfo",//这个是请求的地址
        "fnServerData": retrieveData, // 获取数据的处理函数
        "columns" : [ //处理行数据,这里的data数量必须与<th>的数量一致,否则报错。同时,function中的data包含整行数据信息
        	 { data : "id","visible" : false }, 
        	 { data : function(data, type, full){
        		 return data.province+data.city+data.county+data.address;
        	 }}, 
        	 { data :  function(data, type, full){
        		 return "("+data.ax+","+data.ay+")";
        	 }}, 
        	 {
        	   data :  function(data, type, full){
        		 return "<div class=\"tpl-table-black-operation\">"+
                 "<a href=\"javascript:;\"><i class=\"am-icon-pencil\"></i> 修改</a>"+
                 "<a href=\"javascript:;\"><i class=\"am-icon-pencil\"></i> 管理</a>"+
                 "<a href=\"javascript:;\" class=\"tpl-table-black-operation-del\"><i class=\"am-icon-trash\"></i> 删除</a></div>";
        	 }}
        	 ]
	}); 
});

function retrieveData(sSource,aoData, fnCallback) {
        $.ajax({
        url : sSource,//这个就是请求地址对应sAjaxSource
        data : {"aoData":JSON.stringify(aoData)},//这个是把datatable的一些基本数据传给后台,比如起始位置,每页显示的行数
        type : 'post',
        dataType : 'json',
        async : false,
        success : function(result) {
            fnCallback(result);//把返回的数据传给这个方法就可以了,datatable会自动绑定数据的
        },
        error : function(msg) {
             //报错执行方法
        }
    });
}

       此时后台接收到的请求JSON信息为:

aoData=[{"name":"sEcho","value":1},
{"name":"iColumns","value":4},
{"name":"sColumns","value":",,,"},
{"name":"iDisplayStart","value":0},
{"name":"iDisplayLength","value":10},
{"name":"mDataProp_0","value":"id"},
{"name":"mDataProp_1","value":"name"},
{"name":"mDataProp_2","value":"disname"},
{"name":"mDataProp_3","value":"function"}]

       其中,有用的信息为sEcho(不知道为什么,就是有用),iDisplayStart:请求数据的初始位,IDisplayLength为每页行数。本人默认使用10行分页,有需要的人可以自行提取次数据。本人后台方法(JFinal)如下,SpringMvc差不多,参考一下就行:

public void getHouseInfo(){
	Map<String, Integer> map = DataTableUtil.getPageNo(getPara("aoData"));
	Page<House> list = houseService.pageHouse(map.get("iDisplayStart")/10+1, 10);//因为datatables请求后台只提供请求初始位置信息(如10个分页,那第一页请求信息为0,第二页为10,第三页为20)。这个方法是JFinal的分页方法,第一个参数为页数,第二个参数为每页行数。若不按10条分页,请提取IDisplayLength参数,替换数据10。
	renderJson(DataTableUtil.dataType(list, map.get("sEcho")));
}

private static Map<String, Integer> map = new HashMap<>();
private static JSONObject getObj = new JSONObject();

//提取JSON数据中有用的信息
public static Map<String, Integer> getPageNo(String json){
	JSONArray jsonarray = JSONArray.parseArray(json); 
	for (int i = 0; i < jsonarray.size(); i++) {
	JSONObject obj = (JSONObject) jsonarray.get(i);
	if (obj.get("name").equals("sEcho"))
	     map.put("sEcho", Integer.parseInt(obj.getString("value")));
	if (obj.get("name").equals("iDisplayStart"))
	     map.put("iDisplayStart", Integer.parseInt(obj.getString("value")));
	}
    return map;
}

//回传数据信息,需按照datatables的数据格式返回信息
public static <E> String dataType(Page<E> page,Integer pageNum){
	List<E> list = page.getList();
	getObj.put("sEcho", pageNum);// 不知道这个值有什么用,有知道的请告知一下
	getObj.put("iTotalRecords", list.size());//每页行数
	getObj.put("iTotalDisplayRecords",page.getTotalRow());//分页的总行数
    getObj.put("aaData", list);//分页信息
    return getObj.toString();
}

       接下来我们说第二种分页方法,这种分页方法比较好用,支持随意向后台传递自定义数据,并支持手动刷新datatables。代码如下:

var datatable
$(function(){ 
	datatable=$('#list').DataTable({
		"searching": false,
		"bLengthChange": false,
		"ordering": false,
		"serverSide": true,//这个用来指明是通过服务端来取数据
		"processing": true, //打开数据加载时的等待效果  
        "ajax":{
        	"url": "#(ctx)/admin/getHouseInfo",   
            "type":"post",
            "data": function ( d ) {  
                var level1 = $('#search').val();  //此处为外部搜索框信息
                //添加额外的参数传给服务器  
                d.extra_search = level1;  
                return {"aoData":JSON.stringify(d)};
            }  
        },
        "columns" : [ 
        	 { data : "id","visible" : false }, 
        	 { data : function(data, type, full){
        		 return data.province+data.city+data.county+data.address;
        	 }}, 
        	 { data :  function(data, type, full){
        		 return "("+data.ax+","+data.ay+")";
        	 }}, 
        	 {
        	   data :  function(data, type, full){
        		 return "<div class=\"tpl-table-black-operation\">"+
                 "<a href=\"javascript:;\"><i class=\"am-icon-pencil\"></i> 修改</a>"+
                 "<a href=\"javascript:;\"><i class=\"am-icon-pencil\"></i> 管理</a>"+
                 "<a href=\"javascript:;\" class=\"tpl-table-black-operation-del\"><i class=\"am-icon-trash\"></i> 删除</a></div>";
        	 }}
        	 ]
	}); 
});
//搜索框的搜索按钮点击事件。其它地方想刷新datatables直接使用里面的方法就好。
$("#searchBtn").on('click',function(){
	datatable.ajax.reload();
});

       此时,后台接收到的JSON信息与第一个方法完全不一样:

aoData={"draw":1,
"columns":[{"data":"id","name":"","searchable":true,"orderable":false,"search"{"value":"","regex":false}},{"data":"function","name":"","searchable":true,"orderable":false,"search":{"value":"","regex":false}},{"data":"function","name":"","searchable":true,"orderable":false,"search":{"value":"","regex":false}},{"data":"function","name":"","searchable":true,"orderable":false,"search":{"value":"","regex":false}}],
"order":[],
"start":0,
"length":10,
"search":{"value":"","regex":false},
extra_search":""}

       可以看到有用信息为start(初始位置),length(每页长度),extra_search(额外传送参数)。

       所以,本人的JFinal后台如下写:

public void getHouseInfo(){
	Map<String, Integer> map = DataTableUtil.getPageNoAjax(getPara("aoData"));
	Page<House> list = houseService.pageHouse(map.get("iDisplayStart")/10+1, 10);
    renderJson(DataTableUtil.dataTypeAjax(list));
}


private static Map<String, Integer> map = new HashMap<>();
private static JSONObject getObj = new JSONObject();

//目前我是按照10行分页,有需要的按照其他行数分页的请提取参数length
public static Map<String, Integer> getPageNoAjax(String json){
	JSONObject jobject = JSONObject.parseObject(json);
    map.put("iDisplayStart", Integer.parseInt(jobject.getString("start")));
	return map;
}

//返回数据,与第一种返回数据格式不一样
public static <E> String dataTypeAjax(Page<E> page){
	List<E> list = page.getList();
	getObj.put("iTotalRecords", list.size());//每页的行数
	getObj.put("iTotalDisplayRecords",page.getTotalRow());//分页总行数
	getObj.put("aaData", list);//分页内容信息
	return getObj.toString();
}

       本人写的SpringMvc后台如下:

@RequestMapping("getHouseInfo")
@ResponseBody
public DataTableViewPage<House> getPageList(String aoData) {
	Map<String, Object> param = houseservice.getExtraParam(aoData);//获取相关参数
	String search = (String) param.get("extra_search");//获取搜索框参数
	Pageable pageable = houseservice.getPageable(aoData);//获取分页信息
	Page<House> housepage = null;
	if (search.isEmpty())
		housepage = houseservice.getAllHouse(pid,pageable);
	else 
		housepage = houseservice.getHouseBySearch(search, pageable);
	return new DataTableViewPage<House>((int) housepage.getTotalElements(), housepage.getSize(), housepage.getContent());
}

//获取参数
@Override
public Map<String, Object> getExtraParam(String json) {
	Map<String, Object> map = new HashMap<String, Object>();
	JSONObject jo = JSONObject.parseObject(json);
	map.put("extra_search", jo.getString("extra_search"));
	return map;
}

//获取分页信息
@Override
public Pageable getPageable(String json) {
	JSONObject jo = JSONObject.parseObject(json);
	int pageNo = jo.getIntValue("start") / 10;
	Pageable pageable = new PageRequest(pageNo, 10);
	return pageable;
}

//返回数据类型DataTableViewPage
public class DataTableViewPage<T> {
	
	private List<T> aaData;
	private Integer iTotalDisplayRecords;   
    private Integer iTotalRecords;  
    
    public DataTableViewPage(Integer iTotalDisplayRecords,Integer iTotalRecords,List<T> aaData){
    	this.aaData = aaData;
    	this.iTotalDisplayRecords=iTotalDisplayRecords;
    	this.iTotalRecords = iTotalRecords;
    }

	public List<T> getAaData() {
		return aaData;
	}

	public void setAaData(List<T> aaData) {
		this.aaData = aaData;
	}

	public int getiTotalDisplayRecords() {
		return iTotalDisplayRecords;
	}

	public void setiTotalDisplayRecords(int iTotalDisplayRecords) {
		this.iTotalDisplayRecords = iTotalDisplayRecords;
	}

	public int getiTotalRecords() {
		return iTotalRecords;
	}

	public void setiTotalRecords(int iTotalRecords) {
		this.iTotalRecords = iTotalRecords;
	}
}