JeeSite 4.x

Spring Boot 最好的快速开发平台

数据表格 API、jqGrid、DataGrid组件

数据表格是一个必不可少的元素,在选择这个选型的时候尝试了很多开源组件,最终选择jqGrid,只是因为它接近经典思维,用着还算顺手,最主要的是遇见什么问题都可以自行解决和修复问题,有人说jqGrid不好看,这没关系这完全而已自行编写CSS改造它。 支持:分页,排序,多表头,分组,子表,冻结,小计,合计,编辑行,树表表格等;

最简单的一个例子

<% layout(... libs: ['dataGrid'] ...}){ %>
<#form:form id="searchForm" model="${config}" action="${ctx}/sys/config/listData" method="post" class="form-inline "
		data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
	参数名称:<#form:input path="configName" maxlength="100" class="form-control" />
	参数键名:<#form:input path="configKey_like" maxlength="100" class="form-control" />
	<button type="submit" class="btn btn-primary btn-sm">查询</button>
	<button type="reset" class="btn btn-default btn-sm">重置</button>
</#form:form>
<table id="dataGrid"></table>
<div id="dataGridPage"></div>

JS:

// 初始化DataGrid对象
$('#dataGrid').dataGrid({
    // 查询数据表单
    searchForm: $('#searchForm'),
	// 设置数据表格列
	columnModel: [ 
		{header:'参数名称', name:'configName', index:'a.config_name', width:200, formatter: function(val, obj, row, act){
			return '<a href="${ctx}/sys/config/form?id='+row.id+'" class="btnList" data-title="编辑参数">'+val+'</a>';
		}},
		{header:'参数键名', name:'configKey', index:'a.config_key', width:200},
		{header:'参数键值', name:'configValue', sortable:false, width:260, classes:"nowrap"},
		{header:'操作', name:'actions', width:100, sortable:false, title:false, formatter: function(val, obj, row, act){
			var actions = [];
			<% if(hasPermi('sys:config:edit')){ %>
				actions.push('<a href="${ctx}/sys/config/form?id='+row.id+'" class="btnList" title="编辑参数"><i class="fa fa-pencil"></i></a>&nbsp;');
			<% } %>
			<% if(hasPermi('sys:config:delete')){ %>
				actions.push('<a href="${ctx}/sys/config/delete?id='+row.id+'" class="btnList" title="删除参数" data-confirm="确认要删除该参数吗?"><i class="fa fa-trash-o"></i></a>&nbsp;');
			<% } %>
			return actions.join('');
		}}
	],
	// 加载成功后执行事件
	ajaxSuccess: function(data){
		
	}
});

是不是比你使用foreach方便的多,封装后名字叫dataGrid,这只是展示了冰山一角,它支持所有jqGrid参数,即简化了代码编写,又不失功能

常用选项

options = $.extend({

    // 数据表格参数
    url: searchForm.attr('action'),
    postData: searchForm.serializeArray(),
    mtype: "POST", datatype: "json",
    editurl: 'clientArray', // 单行编辑的时候使用本地数组形式
    rowNum: -1, 		    // 显示行数,-1为显示全部
    rownumWidth: 30,		// 序号列宽
    // multiboxonly: true,	// 单击复选框时再多选
    altRows: true, 		    // 斑马线样式,交替行altclass
    
    // 设置自定义列模型参数(columnModel包含colNames和colModel官方自带属性)
    columnModel: [], colNames: [], colModel: [],

    // 设置数据表格扩展参数
    dataId: 'id', 		// 指定数据主键,当主键名称不是id的时候设置
    lazyLoad: false, 	// 是否懒加载Grid数据,默认初始列表后不及时加载数据,(仅对url远程请求数据有效),当调用 dataGrid.refresh()时再进行加载。
    shrinkToFit: true, 	// 是否按百分比自动调整列宽,当列比较多时可设置为false
    
    showRownum: true,	// 是否显示行号
    showCheckbox: false,// 是否显示复选框
    sortableColumn: true,// 列表是否允许排序(设置为false后,整个列表不允许排序)
    
    // 表格大小设置参数,autoGridHeight 和 autoGridWidth 可以是个函数,函数的返回值就是该表格的高度或宽度。
    autoGridHeight: true, // 自动表格高度(设置为false后,不自动调整表格高度),为函数时返回'100%',则自动高度。
    autoGridHeightFix: 0, // 自动表格高度宽度(自动调整高度时修正的高度值)
    autoGridWidth: true,  // 自动表格宽度(设置为false后,不自动调整表格宽度)
    autoGridWidthFix: 0,  // 自动表格修复宽度(自动调整宽度时修正的宽度值)
    
    // 窗体按钮绑定(不使用默认按钮或按钮ID不同时设置)
    btnSearch: $("#btnSearch"), 					// 查询按钮
    btnRefreshTree: $("#btnRefreshTree"), 			// 刷新树按钮
    btnExpandTreeNode: $("#btnExpandTreeNode"), 	// 展开树节点按钮
    btnCollapseTreeNode: $("#btnCollapseTreeNode"), // 折叠树节点按钮
    
    // 编辑表格参数
    editGrid: false,					// 是否是编辑表格
    editGridInitRowNum: 1,				// 编辑表格的初始化新增行数
    editGridInitAllRowEdit: true,		// 是否初始化就编辑所有行
    editGridAddRowBtn: $("#"+dataGridId+"AddRowBtn"),	// 子表增行按钮
    editGridAddRowInitData: {},			// 新增行的时候初始化的数据(支持函数或对象)
    
    // 编辑表格的提交数据参数
    editGridInputForm: dataGrid.parents('form'), // 提交表单的ID(当前grid所在表单)
    editGridInputFormListName: '', // 提交的数据列表名,例如:testDataChildList
    editGridInputFormListAttrs: '', // 提交数据列表的属性字段,例如:id,status,name,remarks
    
    // 树结构表格参数
    treeGrid: false,							// 启用树结构表格
    treeGridModel: 'adjacency',					// 启用简单结构模式
    treeColumn: null,							// 需要展开的列(默认第一列)
    ExpandColClick: true,						// 隐含参数,请不要设置,单击列可展开
    ExpandColumn: options.treeColumn,			// 隐含参数,请不要设置,需要展开的列
    defaultExpandLevel: 0,						// 默认展开的层次
    initExpandLevel: options.defaultExpandLevel,// 保存初始化是设置的展开层次
    expandNodeClearPostData: false, // 展开节点清理请求参数数据,设置为true请求地址只包含parentCode参数,设置为字符串参考(dictList.jsp)只清理指定的参数
    
    // 分页相关字段(设置分页参数input对象)
    inputPageNo: $("#pageNo", searchForm),		// 当前页码字段
    inputPageSize: $("#pageSize", searchForm),	// 页面大小字段
    inputOrderBy: $("#orderBy", searchForm),	// 排序字段

    // 设置多级表头
    groupHeaders: {
     	twoLevel:[
     		{startColumnName: 'postCode', numberOfColumns: 2, titleText: '二级表头'},
     		{startColumnName: 'remarks', numberOfColumns:2, titleText:'二级表头2'}
     	],
     	threeLevel:[
     		{startColumnName: 'postCode', numberOfColumns:4, titleText:'三级表头'}
     	]
    },
    frozenCols: true, 	// 冻结列,锁定列,在 colModel 指定 frozen: true
    showFooter: true,	// 是否显示底部合计行

}, options);

常用事件

options = $.extend({

    // 选择行后调用(id:行id,isSelect:是否是选中,event:事件)
    onSelectRow: function(id, isSelect, event) {
    },

    // 单击列表表头上的全选按钮时调用(ids:选中的id数组,isSelect:是否选中)
    onSelectAll: function(ids, isSelect){
    },

    // 双击表格行时调用(id:双击的行号,rownum:双击的行位置,column:双击的列)
    ondblClickRow: function(id, rownum, colnum, event){
    },
    
    // 展开节点事件
    onExpandNode: function(data){
    },

    // 折叠节点事件
    onCollapseNode: function(data){
    },

    // 数据加载前执行方法
    ajaxLoad: function(data){
    },

    // 数据加载成功后执行方法
    ajaxSuccess: function(data){
    },

    // 数据加载失败后执行方法
    ajaxError: function(data){
    },

    // 表格初始化完成后执行
    complete: function(){
    }

}, options);

常用方法

调用示例

// 该调用方式,支持调用 jqGrid 原生方法,与 $('#jqgrid').jqGrid('方法名') 相同
$('#列表对象id').dataGrid('方法名', '参数1', '参数2', '参数3', '参数4', '参数5...等等');

设置参数

// params:设置参数值,如:{url: '/sys/user/listData'}
// overwrite:是否重写,如果设置参数为数组,则直接替换,不进行深度拷贝,原理如下:
//    if(overwrite === true) {
//        var params = $.extend({}, this.p, newParams);
//        this.p = params;
//    } else {
//        $.extend(true,this.p,newParams);
//    }
$('#dataGrid').dataGrid('setParam', params, overwrite);

// 举例:datatype为local时,则更新数据方法为:
$('#roleGrid').dataGrid('setParam', {data:[{},{},{}]}, true);
$('#roleGrid').dataGrid('refresh');

获取参数

$('#dataGrid').dataGrid('getParam', paramName);

获取所有数据ID

$('#dataGrid').dataGrid('getDataIDs');

获取某一行数据

$('#dataGrid').dataGrid('getRowData', rowId);

获取全部行数据

$('#dataGrid').dataGrid('getRowData');

获取选择行ID

$('#dataGrid').dataGrid('getSelectRow');

获取选择行数组ID

$('#dataGrid').dataGrid('getSelectRows');

设置选择行

// isCancel: 是否是取消选中
$('#dataGrid').dataGrid('setSelectRow', id, isCancel);

刷新表格(带分页)

$('#dataGrid').dataGrid('refresh', pageNo, pageSize);

只刷新表格(重新载入)

$('#dataGrid').dataGrid('reloadGrid');

删除当前行(普通列表用)

$('#dataGrid').dataGrid('delRowData', id);

删除树节点(树结构用)

$('#dataGrid').dataGrid('delTreeNode', id);

展开树节点

// level:一次展开的层次(数值)
$('#dataGrid').dataGrid('expandTreeNode', level);

折叠树节点

$('#dataGrid').dataGrid('collapseTreeNode');

获取孩子节点

$('#dataGrid').dataGrid("getNodeChildren", rowId);

刷新树表格

// expandLevel: 展开的层级, parentCode:跟节点编号(只显示哪一级)
$('#dataGrid').dataGrid('refreshTree', expandLevel, parentCode);

刷新树的子节点

// rowid 行号
// currentRowid 当前节点id,然后再重新加载新的父节点
$('#dataGrid').dataGrid('refreshTreeChildren', rowid, currentRowid);

显示隐藏列

$('#dataGrid').dataGrid('hideCol', '列名'); //隐藏列
$('#dataGrid').dataGrid('showCol', '列名'); //显示列

合并单元格

1、合并相同数据行

在加载完成数据之后调用 mergeCell 方法:

ajaxSuccess: function(data){
    // 第二个参数指定,合并的单元格列名(多个用逗号分隔,如:'company.companyNameSimple,office.officeName')
    $('#dataGrid').dataGrid('mergeCell', 'company.companyNameSimple,office.officeName');
}

2、合并指定数据列:

根据加载的数据设置单元格属性:

columnModel: [{
    name:'a', index:'a', width:50,
    cellattr: function(rowId, tv, rawObject, cm, rdata) {
        if (rowId == '123') { return ' colspan=2' }
    }
},{
    name:'b', index:'b', width:50,
    cellattr: function(rowId, tv, rawObject, cm, rdata) {
        if (rowId == '123') { return ' style="display:none;"' }
    }
}]

更新列表字段名字

// 提交子表前,更新列表字段名字,以方便后台接受(多行编辑)
// fieldNames:多个用逗号分隔,如:'id,name,remarks'
$('#dataGrid').dataGrid('updateListFieldName', cellNames);

表格合计行

1、设置 options 选项如下:

showFooter: true, // 是否显示底部合计行

2、合计行数据来源有两种方式

a) 第一种是: 后台添加如下代码

page.addOtherData("user.userName", "<em>合计:&nbsp;</em>");
page.addOtherData("sex", "<em>100 &nbsp;</em>");
page.addOtherData("remarks", "<em>¥1000 &nbsp;</em>");

返回的数据格式如下:

{"pageNo":1,
    "pageSize":30,
    "list":[ 返回结果集数据... ],
    "otherData":{ // 此属性为合计行数据集(列名对应合计行数据)
        "user.userName":"<em>合计:&nbsp;</em>"}
        "sex":"<em>100 &nbsp;</em>"}
        "remarks":"<em>¥1000 &nbsp;</em>"
}

b) 第二种是:请求完成之后通过js设置,举例如下:

ajaxSuccess: function(data){ // 加载成功后执行方法
    // 设置底部合计行数据(设置合计行)
    $('#dataGrid').dataGrid("footerData", "set", {
        'user.userName' : '<em>合计:&nbsp;</em>',
        'sex': '<em>100 &nbsp;</em>',
        'remarks': '<em>¥1000 &nbsp;</em>'
    }, false);
}

列表列格式化设置

// 金额、货币、数量、千分位显示
{header:'金额', name:'price', formatter:'integer', formatoptions:{thousandsSeparator:',', defaulValue:''}},
{header:'货币', name:'price', formatter:'currency', formatoptions:{thousandsSeparator:',', decimalSeparator:'.', decimalPlaces:2, defaulValue:'', prefix:'¥'}},  
{header:'数量',  name:'amount', formatter:'number', formatoptions:{thousandsSeparator:',', decimalPlaces:3, defaulValue:''}},
// 日期类型格式化(原格式:yyyy-MM-dd HH:mm:ss  转换为:yyyy-MM-dd HH:mm)
{header:'更新时间', name:'updateDate', formatter:"date", formatoptions:{srcformat:'Y-m-d H:i:s', newformat:'Y-m-d H:i'}},

formatter:主要是设置格式化类型(integer、email等以及函数来支持自定义类型)

formatoptions:用来设置对应 formatter 的参数,jqGrid 中预定义了常见的格式及其 options 如下:

  • integer
    • thousandsSeparator: //千分位分隔符,
    • defaulValue
  • number
    • decimalSeparator, //小数分隔符,如”.”
    • thousandsSeparator, //千分位分隔符,如”,”
    • decimalPlaces, //小数保留位数
    • defaulValue
  • currency
    • decimalSeparator, //小数分隔符,如”.”
    • thousandsSeparator, //千分位分隔符,如”,”
    • decimalPlaces, //小数保留位数
    • defaulValue,
    • prefix //前缀,如加上”$”
    • suffix//后缀
  • date
    • srcformat, //source的本来格式
    • newformat //新格式
  • email
    • 没有参数,会在该cell是email加上: mailto:name@domain.com
  • showlink
    • baseLinkUrl, //在当前cell中加入link的url,如”jq/query.action”
    • showAction, //在baseLinkUrl后加入&action=actionName
    • addParam, //在baseLinkUrl后加入额外的参数,如”&name=aaaa”
    • target,
    • idName //默认会在baseLinkUrl后加入,如”.action?id=1”。改如果设置idName=”name”,那么”.action?name=1”。其中取值为当前rowid
  • checkbox
    • disabled //true/false 默认为true此时的checkbox不能编辑,如当前cell的值是1、0会将1选中
  • select
    • 设置下拉框,没有参数,需要和colModel里的editoptions配合使用

使用本地数据渲染

1、关键属性:

data: [{k:'v1'},{k:'v2'}],  // 本地数据(JSON格式)
datatype: "local",          // 设置数据类型为,local(本地数据)
rowNum: 1000                // 设置最大显示行数(如果不设置,默认为1000)

2、演示例子:

// 用户编辑的选择角色示例
$("#roleGrid").dataGrid({
    data: ${toJson(roleList)},
    datatype: "local",
    columnModel: [
        {header:'角色名称', name:'roleName', sortable:false, width:100},
        {header:'角色编码', name:'roleCode', sortable:false, width:100} 
    ],
    showCheckbox: true, // 显示复选框
    autoGridHeight: function(){
        return 'auto'; // 高度为自动高度
    },
    autoGridWidth: function(){
        return $('#inputForm .tab-content').width(); // 相对宽度
    }
});
// 复选框,选择行相应行
var ids = "${user.roleCodes}".split(",");
for(var i=0; i<ids.length; i++) {
    $("#roleGrid").dataGrid('setSelectRow', ids[i]);
}
//获取选中角色ID字符串
$("#roleGrid").dataGrid('getSelectRows').join(',');

动态数据、动态列模型

// 动态追加数据
var data = [];
data.push({'roleName':'普通员工','roleCode'});
data.push({'roleName':'普通员工','roleCode'});

// 动态生成列模型
var columnModel = [];
columnModel.push({header:'角色名称', name:'roleName', sortable:false, width:100});
columnModel.push({header:'角色编码', name:'roleCode', sortable:false, width:100});

// 生成表格
$("#roleGrid").dataGrid({
    data: data,  // 应用动态生成的数据
    datatype: "local",
    columnModel: columnModel, // 应用动态生成的列模型
    showCheckbox: false
});

选择编辑行、单行编辑

// 选择行后,设置为编辑行
onSelectRow: function(id) {
    if (id){
        // 选择行后,编辑此行数据
        var dg = $('#dataGrid');
        if (window.lastSelRow != id){
            dg.dataGrid('saveRow', window.lastSelRow);
            dg.dataGrid('editRow', id, {keys:true, focusField:false});
            window.lastSelRow = id;
        }
    }
},

删除按钮自定义回调

actions.push('<a href="${ctx}/sys/config/delete?id=' + row.id + '" class="btnList" title="删除参数"'
    + ' data-confirm="确认要删除该参数吗?" data-confirm-success="alert(\'我是回调\')">'
    + '<i class="fa fa-trash-o"></i></a>&nbsp;');

保存表单后刷新列表

$("#inputForm").validate({
	submitHandler: function(form){
		// 发送异步提交表单请求
		js.ajaxSubmitForm($(form), function(data){
			// 保存表单后提示结果消息
			js.showMessage(data.message);
			// 如果提交结果为true,则代表保存成功
			if(data.result == Global.TRUE){
				// 保存成功,后关闭当前Tab页签
				js.closeCurrentTabPage(function(contentWindow){
					// 这里是,在关闭当前Tab页签之前执行的回调方法
					// 参数 contentWindow 返回的是上一个Tab页签的 window 对象
					// 调用上一个页签window对象里的page()方法,刷新grid数据
					contentWindow.page();
				});
			}
		}, "json");
	}
});