目前,网络上能够找得到的、基于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>
- </div>
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,
- // 设置超时,单位毫秒
- timeout:1000,
- // 设置表格中文信息显示
- 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推出来的,现在快一年了还没见更新。