目前,网络上能够找得到的、基于jQuery 框架 的、功能 比较强大的grid有两个:jqGrid和 Flexigrid。虽然这两个表格插件 没有Ext-Grid表格功能那么强大,但基本能满足日常应用 。jqGrid的用法石头在《封装了 jqGrid为control,大家用用看? 》的贴子里已做了具体介绍,在此我不再赘言。Flexigrid的功能比jqGrid稍弱,但胜在界 面美观(仿Ext),易于上手。下面我就Flexigrid在FleaPHP 下的使用方法进行具体说明。
一、Flexigrid的新特性:
- 可调整大小的列
- 可调整大小的高度和宽度
- 可排序的列标题
- 酷主题
- 可 将普通表格转换成grid
- 能够连接到一个AJAX 数据 源( 支持XML和JSON [新] )
- 分 页
- 显示/隐藏列
- 工具栏(新)
- 搜索(新)
- 可访问 的API
二、相关代码 下载 :
- 官方网站:http://www.flexigrid.info , 由于开发 者没有自己的主机,主页空间是申请的,因此官方网站经 常变换,这个不久之后很有可能变成死链。
- 最新源代码(目前为1.0B3)下载:http://code.google.com/p/flexigrid/ , 这个就不会经常变换了。
- jQuery框架代码下载:http://code.google.com/p/jqueryjs/downloads/list 。
- jQuery UI 下载:http://jqueryui.com/themeroller/ , 下载之前,最好先定制好自己喜欢的主题风格再下载。
- jQuery表单 插件下载:http://www.malsup.com/jquery/form/#download 。
- jQuery alert插件下载:http://abeautifulsite.net/notebook_files/87/jquery.alerts.zip 。
三、代码安装:
代码安装比较简单,将代码解压缩到自己项目 的相应子目录 下即可,我这里是lib/jquery目录。
四、使用方法:
1、为了不将大家弄迷糊,且便于后续介绍,容我先将用到的数据表单视图 代码贴出来。
CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(10) unsigned NOT NULL auto_increment,
`unit_id` int(10) unsigned NOT NULL default '0',
`jg_id` int(10) unsigned NOT NULL default '0',
`username` varchar(8) NOT NULL default '',
`password` varchar(64) NOT NULL default '',
`name` varchar(10) NOT NULL default '',
`class` enum('0','1') NOT NULL default '0',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`updated` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`user_id`)
)
说 明:数据库 与数据表均为 GB2312 编码 格式创建。
2、制作模板 文件 (Smarty)
由于Smarty要将JavaScript代码里的url 进行转换,因此我将xhtml 模 板代码跟JavaScript合并在一起组成一个模板文件。如果你将JavaScript代码里的URL写实,也可以将JavaScript代码写入文件 中,然后通过<script type="text/javascript" src="lib/jquery/your_js_file.js"></script>的方式引用。
xhtml代码:
<link rel="stylesheet" type="text/css" href="lib/jquery/ui/css/cupertino/jquery-ui-1.7.1.custom.css"> <link rel="stylesheet" type="text/css" href="lib/jquery/flexigrid/css/flexigrid/flexigrid.css"> <script type="text/javascript" src="lib/jquery/jquery-1.3.2.min.js"></script> <script type="text/javascript" src="lib/jquery/jquery-ui-1.7.1.custom.min.js"></script> <script type="text/javascript" src="lib/jquery/jquery.form.js"></script> <script type="text/javascript" src="lib/jquery/flexigrid/flexigrid.js"></script> <!-- //jquery.alerts --> <link rel="stylesheet" type="text/css" href="lib/jquery/alerts/jquery.alerts.css"> <script type="text/javascript" src="lib/jquery/alerts/jquery.alerts.js"></script> <style> .flexigrid div.fbutton .add { background: url(lib/jquery/flexigrid/css/images/row_add.gif) no-repeat center left; } .flexigrid div.fbutton .edit { background: url(lib/jquery/flexigrid/css/images/row_edit.gif) no-repeat center left; } .flexigrid div.fbutton .delete { background: url(lib/jquery/flexigrid/css/images/row_delete.gif) no-repeat center left; } .flexigrid div.fbutton .reset { background: url(images/user_reset.gif) no-repeat center left; } .flexigrid div.fbutton .excel { background: url(images/excel.gif) no-repeat center left; } #dialog_div { text-align: left; padding-left: 20px; margin: 0px; padding-top: 10px; background-color: #E3F0EA; } #dialog_form { margin: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; font-style: normal; } #dialog_form input.txt { font-family: Arial, Helvetica, sans-serif; font-size: 12px; font-style: normal; } </style> <!-- // 数据显示表格 --> <table id="grid"></table> <!-- // 添加/修改数据对话框 --> <div id="dialog_div" style='display:none'> <form id="dialog_form" name="dialog_form" action=""> <input name="user_id" type="hidden" id="user_id" value="" /> <label>用户工号: <input name="username" type="text" class="txt" id="username" /> </label> <br /><br /> <label>真实姓名: <input name="name" type="text" class="txt" id="name" /> </label> <br /><br /> {{if $input.unitView}} <label>所属单位: {{$input.html_unit}} </label> <br /><br /> {{/if}} {{if $input.jgView}} <label>所属机构: {{$input.html_jg}} </label> <br /><br /> {{/if}} <label>分配角色: {{$input.html_auth}} </label> </form> javaScript代码: <script type="text/javascript"> $(document).ready(function(){ $("#grid").flexigrid({ url: '{{url controller='User' action='GetJsonData'}}', dataType: 'json', colModel: [ {display: '序号', name : 'seq', width : 40, sortable : false, align: 'center'}, {display: '#ID', name : 'user_id', width : 40, sortable : true, align: 'left', hide: true}, {display: '用户工号', name : 'username', width : 70, sortable : true, align: 'left'}, {display: '真实姓名', name : 'name', width : 60, sortable : true, align: 'left'}, {display: '所属单位', name : 'unitname', width : 100, sortable : false, align: 'left'}, {display: '所属机构', name : 'jgname', width : 100, sortable : false, align: 'left'}, {display: '分配角色', name : 'jgname', width : 80, sortable : false, align: 'left'}, {display: '创建时间', name : 'created', width : 110, sortable : true, align: 'left'}, {display: '更新时间', name : 'updated', width : 110, sortable : true, align: 'left'} ], searchitems: [ {display: '用户工号', name : 'username'}, {display: '用户姓名', name : 'name', isdefault: true} ], sortname: "username", sortorder: "asc", usepager: true, title: '用户工号维护', useRp: true, rp: 20, rpOptions:[10,15,20,25,40], showTableToggleBtn: false, width: 590, height: 400, striped:true, timeout:1000, // onSubmit: addFormData, pagestat: '当前显示记录 {from} 到 {to} 条,共 {total} 条记录', procmsg: '正在处理,请稍等 ...', nomsg:'找不到符合条件的资料!', errormsg:'连接数据库失败!', buttons: [ {name: '添加', bclass: 'add', onpress: opt}, {name: '修改', bclass: 'edit', onpress: opt}, {name: '删除', bclass: 'delete', onpress: opt}, {separator: true}, {name: '重置密码', bclass: 'reset', onpress: opt}, {separator: true}, {name: '导出EXCEL', bclass: 'excel', onpress: opt}, {separator: true} ] }); /** * 添加/修改对话框 */ $('#dialog_div').dialog({ hide:'', //点击取消后隐藏,如果设为true,则无法关闭弹窗。 autoOpen:false, width:360, height:250, //modal:true, //蒙层 //title:'单位资料添加/修改', overlay: { opacity: 0.5, background: "black" }, buttons:{ '提交':function(){ addUpdate(); }, '取消':function(){ $(this).dialog("close"); }, '重置':function(){ $(this).children('form')[0].reset(); } } }); /** * 点击工具条按钮操作 */ function opt(com, grid) { switch (com) { case '添加': $('.ui-dialog-title').text('添加用户工号'); $('#dialog_div').dialog('open').children('form')[0].reset(); break; case '修改': $('.ui-dialog-title').text('修改用户工号'); selected_count = $('.trSelected', grid).length; if (selected_count == 0) { jAlert('请选择一条记录。', '消息提示'); return false; } if(selected_count>1){ jAlert('抱歉每次只能修改一条记录。', '消息提示'); return false; } var data = new Array(); $('.trSelected td', grid).each(function(i){ //$('.trSelected td:nth-child(2) div', grid).each(function(i){ data=$(this).children('div').text(); //data=$(this).text(); }); //alert(data[3]); //form = $('#dialog_div').dialog('open').children('form'); //form.children('input[name=unit_id]').val(data[1]); //form.children('input[name=code]').val(data[2]); //form.children('input[name=name]').val(data[3]); $('#user_id')[0].value = data[1]; $('#username')[0].value = data[2]; $('#name')[0].value = data[3]; $.ajax({ url:'{{url controller='User' action='GetIds'}}', data:{user_id:data[1]}, type:'POST', dataType:'json', success:function(data){ //alert($('#jg_id').options); var unit_slt = $('#unit_id option'); var jg_slt = $('#jg_id option'); var unit_len = unit_slt.length; var jg_len = jg_slt.length; if(unit_len > 0) { setSelected(unit_slt, data.unit_id); } if(jg_len > 0) { setSelected(jg_slt, data.jg_id); } var auth_radio = $('input:radio'); //alert(auth_radio.length); if (auth_radio.length > 0) { setChecked(auth_radio, data.auth); } } }); $('#dialog_div').dialog('open'); break; case '删除': selected_count = $('.trSelected', grid).length; if (selected_count == 0) { jAlert('请选择一条记录。', '消息提示'); return false; } if(selected_count>1){ jAlert('抱歉每次只能删除一条记录。', '消息提示'); return false; } var names = ''; $('.trSelected td:nth-child(4) div',grid).each(function(i){ if(i) { names += ','; } names += $(this).text(); }); var ids = ''; $('.trSelected td:nth-child(2) div',grid).each(function(i){ if(i){ ids += ','; } ids += $(this).text(); }) /* if (ids == '') { alert('请选择删除记录,允许同时选择多条记录。'); return; }*/ /* if(confirm("确认删除[" + names + "]的用户工号吗?")){ del(ids); }*/ jConfirm("确认删除[<font color='#FF0000'>" + names + "</font>]的用户工号吗?", '删除确认', function(btn){ if (btn) { del(ids); } }); break; case '重置密码': selected_count = $('.trSelected', grid).length; if (selected_count == 0) { jAlert('请选择一条记录。', '消息提示'); return false; } if(selected_count>1){ jAlert('抱歉每次只能选择一条记录。', '消息提示'); return false; } var id = $('.trSelected td:nth-child(2) div',grid).text(); /* var ids = ''; $('.trSelected td:nth-child(2) div',grid).each(function(i){ if(i){ ids += ','; } ids += $(this).text(); })*/ reset(id); break; case '导出EXCEL': document.location.href = "{{url controller='User' action='Export'}}"; break; } } /** * 添加记录 */ function addUpdate(){ $('#dialog_form').ajaxSubmit({ //$('#dialog_form').ajaxform({ url:"{{url controller='User' action='Save'}}", type:'POST', dataType:'json', resetForm:true, success:function(){ $('#grid').flexReload(); $('#dialog_div').dialog('close'); }, error:function(data){ jAlert(data.msg, '消息提示'); } }); }; /** * 删除记录 */ function del(ids){ $.ajax({ url:"{{url controller='User' action='Del'}}", data:{ids:ids}, type:'POST', dataType:'json', success:function(){ $('#grid').flexReload(); } }); }; /** * 重置密码 */ function reset(id) { $.ajax({ url:"{{url controller='User' action='Reset'}}", data:{user_id:id}, type:'POST', dataType:'json', success:function(data){ //$('#grid').flexReload(); jAlert("成功重置[" + data.name + "]工号的密码为[123456]。", '消息提示'); //return; }, error:function(data){ jAlert("重置[" + data.name + "]工号的密码失败。", '消息提示') } }); }; // 根据所属单位数据设置已选项 function setSelected(slt, value) { for(var i=0; i<slt.length; i++) { if(slt.value == value) { slt.selected = true; } else { slt.selected = false; } } }; // 根据所属机构数据设置已选项 function setChecked(slt, value) { for(var i=0; i<slt.length; i++) { if(slt.value == value) { slt.checked = true; } else { slt.checked = false; } } }; }); </script>
Flexigrid参数 配置说明:
// 设置远端服务器URL地址 url: '{{url controller='User' action='GetJsonData'}}', // 将发送和接收的数据类型设置为JSON格式 dataType: 'json', // 设置表格表头及数据显示方式 colModel: [ {display: '序号', name : 'seq', width : 40, sortable : false, align: 'center'}, {display: '#ID', name : 'user_id', width : 40, sortable : true, align: 'left', hide: true}, {display: '用户工号', name : 'username', width : 70, sortable : true, align: 'left'}, {display: '真实姓名', name : 'name', width : 60, sortable : true, align: 'left'}, {display: '所属单位', name : 'unitname', width : 100, sortable : false, align: 'left'}, {display: '所属机构', name : 'jgname', width : 100, sortable : false, align: 'left'}, {display: '分配角色', name : 'jgname', width : 80, sortable : false, align: 'left'}, {display: '创建时间', name : 'created', width : 110, sortable : true, align: 'left'}, {display: '更新时间', name : 'updated', width : 110, sortable : true, align: 'left'} ], // 设置快速搜索参数 searchitems: [ {display: '用户工号', name : 'username'}, {display: '用户姓名', name : 'name', isdefault: true} ], // 设置表格标题 title: '用户工号维护', //分页相关参数 usepager: true, useRp: true, rp: 20, rpOptions:[10,15,20,25,40], // 不显示关闭表格窗口按钮 showTableToggleBtn: false, // 设置表格宽度及高度 width: 590, height: 400, // 设置表格数据隔行变色 striped:true, // 设置表格中文信息显示 pagestat: '当前显示记录 {from} 到 {to} 条,共 {total} 条记录', procmsg: '正在处理,请稍等 ...', nomsg:'找不到符合条件的资料!', errormsg:'连接数据库失败!', // 设置表格工具按钮 buttons: [ {name: '添加', bclass: 'add', onpress: opt}, {name: '修改', bclass: 'edit', onpress: opt}, {name: '删除', bclass: 'delete', onpress: opt}, {separator: true}, {name: '重置密码', bclass: 'reset', onpress: opt}, {separator: true}, {name: '导出EXCEL', bclass: 'excel', onpress: opt}, {separator: true} ]
四、后台 PHP 代码(节选):
获取分页数据代码:
/**
* 返回JSON分页数据到前台
*
*/
function actionGetJsonData()
{
$user = $this->user;
$page = ($_POST['page']) ? $_POST['page'] : 1;
$limit = ($_POST['rp'])?$_POST['rp'] : 20;
$sortname = $_POST['sortname'];
$sortorder = $_POST['sortorder'];
if (!$sortname) $sortname = 'username';
if (!$sortorder) $sortorder = 'asc';
$sort = "$sortname $sortorder";
if (!$page) $page = 1;
if (!$limit) $limit = 15;
$offset = ($page-1) * $limit;
$query = $_POST['query'];
$qtype = $_POST['qtype'];
if ($qtype == 'name') {
$query = mb_convert_encoding($query, 'GB2312', 'utf-8');
}
if ($user['RBAC_ROLES'][0] == 'SYSTEM_ADMIN'){
$conditions = array(
array('class', '1', '='),
);
} else {
$conditions = array(
array('unit_id', $user['UNITID'], '=', 'AND'),
array('class', '0', '=')
);
}
if ($query) {
$conditions = array(
array($qtype, '%' . $query . '%', 'LIKE')
);
}
$this->_tblUser->enableLinks();
$rows = $this->_tblUser->findAll($conditions, $sort, array($limit, $offset));
$rs = $this->_tblUser->findAll($conditions);
$total = count($rs);
$json = "";
$json .= "{\n";
$json .= "page: $page,\n";
$json .= "total: $total,\n";
$json .= "rows: [";
$rc = false;
$i = 1;
foreach ($rows as $row) {
if ($rc) $json .= ",";
$json .= "\n{";
$json .= "user_id:'".$row['user_id']."',";
$json .= "cell:['".$i."'";
$json .= ",'".$row['user_id']."'";
$json .= ",'".$row['username']."'";
$json .= ",'".addslashes($row['name'])."'";
$json .= ",'".addslashes($row['unit']['name'])."'";
$json .= ",'".addslashes($row['jgwh']['name'])."'";
$json .= ",'".$row['roles'][0]['rolename_cn']."'";
$json .= ",'".$row['created']."'";
$json .= ",'".$row['updated']."']";
$json .= "}";
$rc = true;
$i++;
}
$json .= "]\n";
$json .= "}";
echo $json;
exit;
}
注 意上面生成 JSON 格式数据的 PHP 代码,必须严格按照这样的格式返回数据,否则 Flexigrid 将无法处理返回的数据。再有,请注意列模型 colModel 里 的 name 参数,与 user 数据表的字段 并不一一对应,但必须与返回的 JSON 数据保持一致。
保存数据代码:
/**
* 保存数据
*
*/
function actionSave()
{
$user = $this->user;
$data = $_POST;
$data['name'] = mb_convert_encoding(trim($data['name']), 'GB2312', 'utf-8');
if ($data['username'] == ''){
//js_alert("请输入操作帐号。",'',$this->_url());
echo "{succees:false,msg:'用户工号不能为空!'}";
return;
}
if (strlen($data['username']) != 8){
//js_alert("您输入的工号不等于8位,请检查后重新增加。",'',$this->_url());
echo "{succees:false,msg:'用户工号不等于8位!'}";
return;
}
if ($data['name'] == ''){
//js_alert("请输入用户名称。",'',$this->_url());
echo "{succees:false,msg:'用户姓名不能为空!'}";
return;
}
if ($data['user_id']=='') {
$data['password'] = '123456';
//$sort = '`user_id` DESC';
}
if ($data['user_id'] == '' && $this->_tblUser->existsUsername(trim($data['username']))) {
//js_alert("该工号已存在,请重新输入。",'',$this->_url());
echo "{succees:false,msg:'该用户工号已存在!'}";
return false;
}
if (isset($data['auth']) && ($data['auth'] == 1 || $data['auth'] == 2)) {
$data['class'] = '1';
}
if (isset($data['auth'])) {
$data['roles'][0] = $data['auth']; // 为更新 users_roles 中间表准备数据
}
if ($user['RBAC_ROLES'][0] != 'SYSTEM_ADMIN') {
$data['unit_id'] = $user['UNITID'];
}
$this->_tblUser->enableLink('roles');
__TRY();
$this->_tblUser->save($data);
$ex = __CATCH();
if (__IS_EXCEPTION($ex)) {
echo "{succees:false,msg:'保存数据失败!'}";
} else {
echo "{succees:true,msg:'保存数据成功!'}";
}
exit;
}
注 意其中的语句 :
$data['name'] = mb_convert_encoding(trim($data['name']), 'GB2312', 'utf-8');
由于 ajax提交的中文数据为 utf-8 编码格式的数据,因此保存到数据表时,须用多字节字符串处理函数 mb_convert_encoding 转换成 GB2312 编码格式的数据。
删除记录代码:
/**
* 删除记录
*
*/
function actionDel()
{
$ids = $_POST['ids'];
if ($this->user['RBAC_ROLES'][0] == 'SYSTEM_ADMIN') {
__TRY();
$this->_tblUser->removeByPkv((int)$ids);
$ex = __CATCH();
} else {
$conditions = array(
array('unit_id', $this->user['UNITID'], '=', 'AND'),
array('user_id', $ids, '='),
);
$this->_tblUser->enableLink('roles');
__TRY();
$this->_tblUser->removeByConditions($conditions);
$ex = __CATCH();
}
if (__IS_EXCEPTION($ex)) {
echo "{succees:false,msg:'删除数据失败!'}";
} else {
echo "{succees:true,msg:'删除数据成功!'}";
}
exit;
}
在此,不使用json_encoding生成返回的分页json 格式数据,因为在 GB2312 环境下使用时,返回的中文数据会乱码 。估计json_encoding生成了 json 数据对象 ,而 json 数据对象在 JavaScript 中是以 utf-8 编码来保存数据,所以导致在 GB2312 环境下会产生中文乱码。而上面的 PHP 代码直接返回的数据是 json 格式的字符串,所以在浏览器显示中文数据时不会产生乱码。
五、存在不足:
Flexigrid存在不足的地方主要有两点:
- 定制搜索功能太弱,但这也是开发者将搜索功能定义 为“Quick Search”的原因。
- 版 本更新维护严重不足,目前最新版本也是2008-7-14推出来的,现在快一年了还没见更新。
六、结束语
石头曾经叫我将Flexigrid封装成QeePHP 插件,但由于我对 Qee PHP的使用还不太熟悉,真是有心无力,无法完成此艰巨的任务了,这一工作留待其他大虾去完成吧。不 过,后来想深一层,将Flexigrid封装成 QeePHP 或 Flea PHP 插件,其通用性如何?倒值得好好分析分析,研究研究。Flexigrid 的使用就介绍到这里吧,不好的地方,请各位水之。
本人论坛贴:http://qeephp.com/bbs/thread-7309-1-1.html
运 行效果图1:
运行效果图2:
运行效果图3:
运行效果图4:
运行效果图5: