thinkphp5集成H-ui后台(三)集成datatables

7 篇文章 0 订阅
2 篇文章 0 订阅
在弄完ztree后,这里没有急着去做博客列表的相关功能,因为涉及要说的插件太多。这里单独的说明下如何集成datatables,并详细解释在当前系统中用到的属性。这里使用一个非常简单的表作为例子(公告列表)。
1、数据库表的设计
CREATE TABLE `mq_notice` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '逻辑主键',
  `title` varchar(100) CHARACTER SET utf8 NOT NULL COMMENT '标题',
  `content` text CHARACTER SET utf8 COMMENT '内容',
  `delete_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0:未删除;1:已删除)',
  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
2、页面结构
这是一个完整的查询列表页面,使用datatables的时候,只要先在页面设计好表头等就可以了。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
{include file="../application/admin/view/header.html" /}
{include file="../application/admin/view/footer.html" /}
<title>公告管理</title>
</head>
<body>
<nav class="breadcrumb"><i class="Hui-iconfont"></i> 首页 <span class="c-gray en">></span> 综合管理 <span class="c-gray en">></span> 公告管理 <a class="btn btn-success radius r" style="line-height:1.6em;margin-top:3px" href="javascript:location.replace(location.href);" title="刷新" ><i class="Hui-iconfont"></i></a></nav>
<div class="page-container">
	<div class="text-c">
		标题:<input  type="text" class="input-text" style="width:250px" placeholder="输入标题" id="title" name="" />
		精确查找<input id="accurateFlg" name="accurateFlg" type="checkBox" value="1" />
		<button type="button" class="btn btn-success radius" id="search" name="search"><i class="Hui-iconfont"></i> 搜公告</button>
	</div>
	<div class="cl pd-5 bg-1 bk-gray mt-20"> 
		<span class="l">
			<a href="javascript:;" οnclick="delete_batch()" class="btn btn-danger radius"><i class="Hui-iconfont"></i> 批量删除</a> 
			<a href="javascript:;" οnclick="notice_add('添加公告','__URL__/notice/toNoticeAdd','','')" class="btn btn-primary radius"><i class="Hui-iconfont"></i> 添加公告</a>
		</span> 
	</div>
	<div class="mt-20">
	<table class="table table-border table-bordered table-hover table-bg table-sort">
		<thead>
			<tr class="text-c">
				<th width="25"><input type="checkbox" id="chkId" name="chkIdAll" value=""></th>
				<th width="40">ID</th>
				<th width="200">公告标题</th>
				<th width="200">发布时间</th>
				<th width="100">操作</th>
			</tr>
		</thead>
		<tbody>
		</tbody>
	</table>
	</div>
</div>
</body>
3、datatables的详细说明
datatables真心很好用,作为jquery的页面元组,个人觉得还是很专业的。这里说点题外话,自己在刚入行(javaweb)的那一两年,对css+div有种爱恨交加的感受,爱是它们的语法很简单,恨的是自己实在没有UI设计的文艺细胞。面对一个小小的后台项目,想在已有的模板上面加点自己的东西,都举步维艰。那时候就有一个想法,有没有一套完整的js系统,有自己的css和图片以及icon等,按照全局的样式,封装成一个一个的表单组件(table、from等),使用的时候,只要拿对应的组件就可以了,并不需要考虑全局的布局和样式问题,自己安心的做接口就行。所以就主动的搜寻到了extjs、easyui等。无奈,要么收费,要么试用的组件不全,要么就是像extjs那样太大了......,最后就一直在jquery的组件中东拼西凑着,虽然没有所谓的统一,但还是用得舒心,也许只是习惯了吧。随着移动互联网的兴起,mvvm模式的成熟,尤其是web前端开发的独立,web工程师终于可以安静的去关心框架和数据库了。扯淡到此为止,这里还是上代码,具体解释在注释中:
<script type="text/javascript" src="__ADMIN__/lib/datatables/1.10.0/jquery.dataTables.min.js"></script> 
<script type="text/javascript">
var table;
$(function(){	
	table = $('.table-sort').dataTable({
		"bStateSave": false,//状态保存
		"bServerSide" : true, //是否启动服务器端数据导入  
		"bFilter": false, //去掉默认自带的搜索框
		"aLengthMenu" : [20, 40, 60],//每页显示行数
		"sAjaxSource" : "__URL__/notice/noticeDatas",//请求后台的url
		/**
		 * fnServerParams函数:
		 * 顾名思义,就是请求后台的参数设置
		 * 大家可以在开发的时候可以用console.log(JSON.stringify(aoData))
		 * 查看下参数结构,我们可以将自己页面的查询条件放入aoData中,如例子所示
		 */
		"fnServerParams" : function(aoData) {
	         aoData.push({
	             "name" : "criteria",
	             "value" : {
	            	 "title" : $("#title").val(),
	                 "accurateFlg" : $("#accurateFlg").prop("checked") ? "1" : ""
	             }
	         });
	     }, 


	    /**
	     * aoColumns 对应于表头和属性赋值等	  
	     *
	     * "mData" :  对应的属性名
	     * "bSortable" : 是否需要排序,默认是true(就是每列表头上的的上、下两个箭头)
	     * "sTitle" : 列名
	     * "sDefaultContent" : 默认值  
	     * "sClass" : 相当于css中的text-align,有text-l、text-c、text-r(左中右)这三个选择
	     */
	    "aoColumns" : [{
		    "mData" : "id"
                    },{
			"mData" : "id",
			"sTitle" : "ID", 
			"sWidth": "40px",
			"sDefaultContent" : "",  
                        "sClass" : "text-c"
		    },{
			"mData" : "title",
			"sTitle" : "标题", 
			"sDefaultContent" : "",  
	                    "sClass" : "text-c"
		    },{
			"mData" : "create_time",
			"sTitle" : "发布时间", 
			"sDefaultContent" : "",  
	                "sClass" : "text-c"
		    },{
			"mData" : "",
			"sTitle" : "操作", 
			"sDefaultContent" : "",  
	                "sClass" : "text-c"
		    }],
		//aoColumnDefs用来设置列的属性,可以指定任何列,我们这里用来设置第一列[0]的复选框
		"aoColumnDefs":[{
                    "sClass": "text-c",
                    "mRender" : function(data,type,full) {
                        return '<input type="checkbox" id="chkId_' + data 
				     + '" name="chkId" value="' + data + '"  style="border:1px solid red"/>';
		    },
                    "bSortable": false,
                    "aTargets": [0]
        }], 
        //columnDefs和oColumnDefs差不多,它们的区别问百度吧    
        "columnDefs": [{ "orderable": false, "targets": 1 }],
        /**
         * fnServerData函数
         * 这个函数很重要,我们可以通过里面的参数类重构页面与服务器的交互方式
         * 总之,里面的ajax由我们配置,大家可以打印参数和回调测试测试
         */
	"fnServerData" : function(sSource, aoData, fnCallback) {
            $.ajax({
                type : 'POST',
                url : sSource,
                async : false,
                data : {
                    "aoData" : JSON.stringify(aoData)
                },
                success : fnCallback,
                error : function(XMLHttpRequest, textStatus, errorThrown) {
                    alert(XMLHttpRequest.status + "," + textStatus);
                }
            });
        },
        /**
         * 大家试想一下这样一个业务场景,我们数据库中存放了性别这一列,数据库中的值
         * 1代表男;0代表女;假设我们没有在php中处理,那么页面显示的时候就会显示1或者是0
         * 这显然是不友好的。
         * fnRowCallback就可以直接在页面完美的解决这场景
         * 说白了,就是获取完行数据以后,我们在页面显示之前,对数据预处理下
         * 例子中只是增加操作列的查看、修改和删除图标与事件
         */
        "fnRowCallback" : function(nRow, aData, iDisplayIndex) { 
			var cstr = "<a title='查看' href='javascript:void(0);' οnclick='notice_edit("+aData.id+",0)' class='ml-5' style='text-decoration:none'><i class='Hui-iconfont'></i></a>" +
        			   "<a title='编辑' href='javascript:void(0);' οnclick='notice_edit("+aData.id+",1)' class='ml-5' style='text-decoration:none'><i class='Hui-iconfont'></i></a>" +
        			   "<a title='删除' href='javascript:void(0);' οnclick='notice_del(this,"+ aData.id +")' class='ml-5' style='text-decoration:none'><i class='Hui-iconfont'></i></a>";
       	
        	$('td:eq(4)', nRow).html(cstr);
        	
            return nRow;
       }
	});	
	
	
	//注册查询按钮事件
	$("#search").bind("click", function () {
        //这里可以做一些js的格式验证
        table.fnDraw();//每次查询,调用fnDraw重绘
    });
});
</script>
4、datatables分页说明
写到这里,大家可能会有疑问,分页、总记录数等这些页面信息怎么体现在页面,或者说后台查询出来的分页数据,怎么给datatables?这个呢,就要从datatables的参数说起了。我们在浏览器后台打印下它的请求参数,如图:


上图中的数据就是:
[
	{"name":"sEcho","value":1},
	{"name":"iColumns","value":5},
	{"name":"sColumns","value":",,,,"},
	{"name":"iDisplayStart","value":0},
	{"name":"iDisplayLength","value":20},
	{"name":"mDataProp_0","value":"id"},
	{"name":"bSortable_0","value":false},
	{"name":"mDataProp_1","value":"id"},
	{"name":"bSortable_1","value":true},
	{"name":"mDataProp_2","value":"title"},
	{"name":"bSortable_2","value":true},
	{"name":"mDataProp_3","value":"create_time"},
	{"name":"bSortable_3","value":true},
	{"name":"mDataProp_4","value":""},
	{"name":"bSortable_4","value":true},
	{"name":"iSortCol_0","value":0},
	{"name":"sSortDir_0","value":"asc"},
	{"name":"iSortingCols","value":1},
	{"name":"criteria","value":{"title":"","accurateFlg":""}}
]
我们可以很清楚的看到iDisplayStart、iDisplayLength这两个属性,里面的值就是mysql分页时候limit 0,20的值。所以后台可以获取aoData中的这两个值来进行翻页处理。
后台怎么获取datatables的翻页数据解决了。那么datatables需要的当前页,总数量等这些页面信息怎么从后台获取呢?它又怎么和数据内容区分呢?这个我们可以到datatables的学习论坛中去查找就是了,这里不卖官子,直接告诉大家:
{
"sEcho":1,//这个参数有意思,下小节封装DataTablesUtil.php会详细说明
"iTotalRecords":100,//实际的总数量
"iTotalDisplayRecords":100,//过滤之后的数量,我们不用datatables的假翻页的话,它和iTotalRecords等价
"aaData":'.....',//当前页的所有结果集
...
}
值得说明的是,不同的datatables的版本,参数名是不一样的,我这边用的是H-ui自带的1.10.0,其他的版本,可以上官网或者百度询问,这里不一一列举。到了这一步,我们书写后台的查询语句就有思路了。
5、封装一个DataTablesUtil.php
如果只有一个系统只有这个页面用到datatables,那么我想谁都不会想着要封装一个工具类,这就是实际开发与普通练习的区别。我们通过第4小节的描述,有很清楚的查询思路。但是当大家仔细观察aoData参数结构的时候,我们可以发现,还可以抽取出一个排序的思路。这里还是说下细节:"mDataProp_xx"封装了每列的名称;"bSortable_xx"封装了当前xx列是否需要排序;"sSortDir_xx"打家看到它的值就知道是存放asc和desc这两个排序方式的;"iSortingCols"就是当前查询具体是哪一列在排序(和数组下标一样从0开始)。所以,我们可以做一个大胆的逻辑,根据这些参数获取到客户在使用的时候点了那列,升序还是降序。下面先上DataTablesUtil.php的完整代码:
<?php
namespace app\common\utils;


/**
 *
 * @author tim
 *        
 */
class DataTablesUtil
{
    //datatable参数下标常量定义
    const ID_DISPLAY_START = 'iDisplayStart'; //开始行
    const ID_DISPLAY_LENGTH = 'iDisplayLength'; //每页显示行数
    const S_ECHO = 'sEcho'; //每页的唯一标识,必须在结果集中传回    
    const ORDER_PREFIX = 'mDataProp_'; //列名前缀
    const ISORTCOL_0 = 'iSortCol_0'; //排列下标
    const SSORTDIR_0 = 'sSortDir_0'; //排列方式
    
    //自定义查询条件key
    const CRITERIA = 'criteria';//和页面中aoData中的查询条件key要一致 
    
    //封装查询条件下标常量定义
    const ORDER = 'order';
    const LIMIT = 'limit';
    
    /**
     * 根据$aoData参数,封装查询条件(筛选_criteria、排序_order、分页_limit)
     * */
    public static function getQueryPageProperty($aoData){
        //json参数转化为数组
        $arr = json_decode($aoData,true);    
        
        //将数据整理为key=>value的关联模式数组
        $dataArr = array();         
        for ($i=0;$i<count($arr);$i++){
            $dataArr[$arr[$i]['name']] = $arr[$i]['value'];
        }
        
        //设置返回的数据
        $iSortCol_0 = $dataArr[DataTablesUtil::ISORTCOL_0];
        $sSortDir_0 = $dataArr[DataTablesUtil::SSORTDIR_0];
        $orderClumn = $dataArr[DataTablesUtil::ORDER_PREFIX.$iSortCol_0];
        
        $pageArr[DataTablesUtil::S_ECHO] = $dataArr[DataTablesUtil::S_ECHO];
        if(empty($orderClumn)){
            $pageArr[DataTablesUtil::ORDER] = '';
        }else{
            $pageArr[DataTablesUtil::ORDER] = $orderClumn.' '.$sSortDir_0.' ';
        }        
        $pageArr[DataTablesUtil::LIMIT] = $dataArr[DataTablesUtil::ID_DISPLAY_START].','.$dataArr[DataTablesUtil::ID_DISPLAY_LENGTH];
        $pageArr[DataTablesUtil::CRITERIA] = $dataArr[DataTablesUtil::CRITERIA];
        
        return $pageArr;        
    }
    
    /**
     * 返回dataTable所需要的json格式数据
     * @param $sEcho 
     * @param $count 
     * @param $data 查询结果集(数组)
     * */
    public static function getJsonPage($sEcho,$count,array $data){
        $json = '{"sEcho":'.$sEcho.',"iTotalRecords":'.$count
        .',"iTotalDisplayRecords":'.$count
        .',"aaData":'.json_encode($data).'}';
        return $json;
    }
    
}
可能是用惯了java,这里封装也完全是按java的开发思维去封装的,在常量上面有些冗余的感觉(因为自己是使用eclipse开发的,代码追踪起来很方便。对于用文本编辑器开发的小伙伴看起来就有些麻烦)。这里说明下,其中getQueryPageProperty函数的作用就是将aoData参数封装成一个类似于以下格式的数组:
{
	'sEcho'=>1,
	'order'=>'id asc',
	'limit'=>'10,20',
	'criteria'=>{'title':'xxx','accurateFlg':1}//就是你在fnServerParams中为aoData参数push的查询条件
}
而getJsonPage函数就不多解释了,返回一个datatables的结果集(包含翻页)
6、后台代码查询
有了封装好的DataTablesUtil.php,那么我们的功能代码就清爽多了。
/**
 * 异步查询数据,返回json格式
 * */
public function noticeDatas(Request $request){
   
    $aoData = $request->param('aoData');
    
    $queryArr = DataTablesUtil::getQueryPageProperty($aoData);        
    
    $criteria = $queryArr[DataTablesUtil::CRITERIA];
    
    //查询条件
    $condition = array();
    $condition['delete_flag'] = '0';
    if(!empty($criteria['title'])){
        if(!empty($criteria['accurateFlg']) && $criteria['accurateFlg'] == 1){
            $condition['title'] = $criteria['title'];
        }else{
            $condition['title'] = ['like','%'.$criteria['title'].'%'];                
        }
    }
    
    //查询当前条件的总数
    $count = Notice::where($condition)->count();


    //查询当前条件的结果集,并分页和排序
    $list = Notice::where($condition)
        ->order($queryArr[DataTablesUtil::ORDER])
        ->limit($queryArr[DataTablesUtil::LIMIT])
        ->select();


    $json = DataTablesUtil::getJsonPage($queryArr[DataTablesUtil::S_ECHO],$count,$list);        
    return json_decode($json); 
}

最后上一张图,看看效果:



  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
========================================================== \根目录 ├── _blank.html 空白页(每次我们都拿空白页去创建,这样比较干净!) ├── _footer.html 页脚公共代码片段 ├── _header.html 头部公共代码片段 ├── _meta.html meta公共代码片段 ├── robots.txt 搜索引擎爬虫配置文件 ├── login.html 管理员登陆 ├── index.html 首页(主框架) ├── welcome.html 我的桌面(默认永远打开的页面) ├── member-开头的 用户相关 ├── artice-开头的 资讯相关 ├── picture-开头的 图片相关 ├── product-开头的 产品相关 ├── page-开头的 页面相关 ├── system-开头的 系统相关 ├── admin-开头的 管理员相关 ├── charts-开头的 统计相关 …… static/ 资源 ├── h-ui/ H-ui特有资源 │ ├── css/ 样式 │ │ ├── H-ui.css H-ui基础样式 │ │ ├── H-ui.min.css H-ui.css 压缩版 │ │ ├── H-ui.ie.css H-ui.css IE低版本兼容补丁 │ ├── images/ 图片资源 │ ├── js/ │ │ ├── H-ui.js H-ui核心脚本 ├── h-ui.admin/ H-ui.admin核心资源 │ ├── css/ 样式 │ │ ├── H-ui.login.css 后台管理员登录页样式 │ │ ├── H-ui.admin.css 后台界面主要样式 │ ├── images/ 图片资源 │ ├── js/ │ │ ├── H-ui.admin.js 后台管理核心脚本 │ ├── skin/ 皮肤资源 │ │ ├── blue 蓝色 │ │ ├── default 黑色(默认) │ │ ├── green 绿色 │ │ ├── orange 橙色 │ │ ├── red 红色 │ │ ├── yellow 黄色 Lib/ 第方插件 ├── jquery jQuery类库(v1.9.1) ├── Hui-iconfont 阿里图标字体库(H-ui定制) ├── jquery.SuperSlide 幻灯片组件 ├── Validform 表单验证插件 ├── jquery.validation 表单验证插件 ├── My97DatePicker 日期插件 ├── datatables 表格插件 ├── nprogress 进度条插件 ├── layer layer弹出层插件 ├── laypage laypage 翻页插件 ├── jquery.contextmenu 右键菜单插件 ├── ueditor 百度编辑器 ├── Highcharts 图表插件 ├── echarts 百度图标插件 ├── datatables 表格排序,检索插件 ├── WebUploader 百度文件上传组件 ├── lightbox2 图片预览组件 ├── html5shiv.js html5插件,让低版本IE支持html5元素 ├── DD_belatedPNG_0.0.8a-min.js 解决IE6png透明 ├── swfobject.js Flash插件 ├── expressInstall.swf 检查flash插件 ├── respond.min.js 让IE兼容media ├── colpick.js 颜色插件 └─temp 测试数据、图片

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值