本人做一个名为“安徽中控”项目时,为快速开发基础数据增删改模块,遂采用EasyUIDatagrid将所有增删改查的操作都集中于表格中,并且所有增删改查操作都集中于泛型对象,从而不必为每个表写具体的增删改查代码。而在做时间编辑时,因为EasyUI DataGrid本身没有或者缺失时间控件编辑功能(有可能easyui版本低),需要另外为其扩展。这个过程中出现了一些问题:
1.行进入编辑状态,但时间控件却没有显示出来。
2.行数据是通过后台对象序列化传到前台,因此时间数据格式为"/Date(1460008088000)/",使得时间显示和编辑出现问题。
为了实现行编辑中嵌入时间控件编辑,首先我在网络上查找了一段扩展代码如下:
<script type="text/javascript">
//datagrid 时间控件编辑器扩展 $.extend($.fn.datagrid.defaults.editors, { timespinner: { init: function (container, options) { var input = $('<input/>').appendTo(container); input.timespinner(options); return input }, getValue: function (target) { var val = $(target).timespinner('getValue'); }, setValue: function (target, value) { $(target).timespinner('setValue', value); }, resize: function (target, width) { var input = $(target); if ($.boxModel == true) { input.resize('resize', width - (input.outerWidth() - input.width())); } else { input.resize('resize', width); } } } }); //datagrid 时间控件编辑器扩展 $.extend($.fn.datagrid.defaults.editors, { datetimebox: {// datetimebox就是你要自定义editor的名称 init: function (container, options) { var input = $('<input class="easyuidatetimebox">').appendTo(container); return input.datetimebox({ formatter: function (date) { return new Date(date).format("yyyy-MM-dd hh:mm:ss"); } }); }, getValue: function (target) { return $(target).parent().find('input.combo-value').val(); }, setValue: function (target, value) { $(target).datetimebox("setValue", value); }, resize: function (target, width) { var input = $(target); if ($.boxModel == true) { input.width(width - (input.outerWidth() - input.width())); } else { input.width(width); } } } }); // 时间格式化 Date.prototype.format = function (format) { /* * eg:format="yyyy-MM-dd hh:mm:ss"; */ if (!format) { format = "yyyy-MM-dd hh:mm:ss"; } var o = { "M+": this.getMonth() + 1, // month "d+": this.getDate(), // day "h+": this.getHours(), // hour "m+": this.getMinutes(), // minute "s+": this.getSeconds(), // second "q+": Math.floor((this.getMonth() + 3) / 3), // quarter "S": this.getMilliseconds() // millisecond }; if (/(y+)/.test(format)) { format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); } for (var k in o) { if (new RegExp("(" + k + ")").test(format)) { format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)); } } return format; };
</script>
在扩展之后,我就引入EasyUI插件进行前台编写后进行测试发现时间控件居然显示不出来,我研究很久发现问题在于列宽太小,将原本显示的时间控件按钮遮挡住,于是这个问题通过调整列宽和设置fitColumns: false解决了。 而后发现后台传过来的时间数据格式是"/Date(1460008088000)/"不能正常显示,又通过在列初始化中的格式化函数中进行相应的处理(引入了datapattern.js,附加在文章最后)进行处理如下。此处应注意是列的格式化函数而不是列时间控件编辑器的格式化函数里进行处理!
{field: 'START_TIME', title: '开始时间', 150, formatter: function (value, row, index) { var reg = /^(d{1,4})(-|/)(d{1,2})2(d{1,2}) (d{1,2}):(d{1,2}):(d{1,2})$/;//时间格式验证yyyy-M-d h:m:s var r = value.match(reg); if (r == null) { return (eval(value.replace(//Date((d+))//gi,"new Date($1)"))).pattern("yyyy-MM-dd hh:mm:ss"); } else { return value; } }, editor: 'datetimebox'//注意此控件只能这么调用否则有大问题,并注意列宽够大并且fitColumns: false }
其中BaseTableHeard.js文件里是公共的对表格初始化设置(附加在文章最后)
<head id="Head1" runat="server"> <title></title> <link href="../JS/jquery-easyui-1.3.5/themes/default/easyui.css" rel="stylesheet"
type="text/css" />
<link href="../JS/jquery-easyui-1.3.5/themes/icon.css" rel="stylesheet" type="text/css" />
<link href="../Common/BaseTableStyle.css" rel="stylesheet" type="text/css" />
<script src="../JS/jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="../JS/jquery-easyui-1.3.5/jquery.easyui.min.js" type="text/javascript"></script>
<script src="../JS/jquery-easyui-1.3.5/locale/easyui-lang-zh_CN.js" type="text/javascript"></script>
<script src="../JS/jquery.json.js" type="text/javascript"></script>
<script src="../JS/datapattern.js" type="text/javascript"></script>
<script src="../JS/jquery-easyui-1.3.5/easyExtend.js" type="text/javascript"></script>
<script src="../JS/BaseTableHeard.js" type="text/javascript"></script>
<script type="text/javascript"> //初始化查询条件begin function initSearch() { $('#btSearch').click(function () { var txtName = $('#txtNM').val(); var whereT; //查询条件对象 if (txtNM) { whereT = { NM: txtName }; } loadGridData(whereT); }); } //初始化查询条件end //initGridData方法begin function initGridData() { //初始化Grid表格begin $('#gridList').datagrid({ fitColumns: false, columns: [[ { field: 'ID', title: '主键', 100, hidden: true }, { field: 'NM', title: '班次名称', 100, editor: { type: 'validatebox', options: { required: true}} }, { field: 'CD', title: 'CD', 100, editor: 'text', hidden: true }, { field: 'CTRL', title: 'CTRL', 100, editor: 'text', hidden: true }, { field: 'USED', title: '状态', 100, formatter: function (value, row, index) { switch (value) { case 'Y': return '在用' break; case 'N': return '停用' break; default: return '在用' break; } }, editor: { type: 'combobox', options: { panelHeight: "auto", valueField: 'key', textField: 'value', data: [{ key: 'Y', value: '在用' }, { key: 'N', value: '停用'}], required: true } } }, {field: 'START_TIME', title: '开始时间', 150, formatter: function (value, row, index) { var reg = /^(d{1,4})(-|/)(d{1,2})2(d{1,2}) (d{1,2}):(d{1,2}):(d{1,2})$/;//时间格式验证yyyy-M-d h:m:s var r = value.match(reg); if (r == null) { return (eval(value.replace(//Date((d+))//gi,"new Date($1)"))).pattern("yyyy-MM-dd hh:mm:ss"); } else { return value; } }, // editor: 'datetimebox'//注意此控件只能这么调用否则有大问题,并注意列宽够大并且fitColumns: false editor: 'datetimebox'//注意此控件只能这么调用否则有大问题 }, {field: 'END_TIME', title: '结束时间', 150, formatter: function (value, row, index) { if(value!=null) { var reg = /^(d{1,4})(-|/)(d{1,2})2(d{1,2}) (d{1,2}):(d{1,2}):(d{1,2})$/;//时间格式验证yyyy-M-d h:m:s var r = value.match(reg); if (r == null) { return (eval(value.replace(//Date((d+))//gi,"new Date($1)"))).pattern("yyyy-MM-dd hh:mm:ss"); } else { return value; } }}, editor: 'datetimebox'//注意此控件只能这么调用否则有大问题 }, { field: 'SHIFT_NUM', title: 'SHIFT_NUM', 100, editor: 'text',hidden:true }, { field: 'ISSEND', title: 'ISSEND', 100, editor: 'text' ,hidden:true} ]] }); //initGridData方法end //加载数据 loadGridData(null); } //initialGrid方法end </script> </head> <body> <div class="context"> <div class="search"> 班次名称:<input type="text" id="txtNM" /> <a id="btSearch" onclick="javascript:void(0);" >查询</a> </div> <div class="list" style="margin: 0px"> <table id="gridList"> </table> <div id="pager"> </div> </div> </div> </body> </html>
附件1:
BaseTableHeard.js
var url = window.location.href; $(function () { initGridHeader(); initGridData(); initSearch(); }); function initGridHeader() { //初始化Grid表格begin var tableHeight = $(document).height() - 100; var lastIndex; var editFlag = false; $('#gridList').datagrid({ // url: '/GetPosList.ashx', singleSelect: true, striped: true, height: tableHeight, window.document.width, rownumbers: true, checkOnSelect: false, selectOnCheck: false, fitColumns: true, showFooter: true, // frozenColumns: [[ // { field: 'ck', checkbox: true }, // ]], toolbar: [{ text: '新增', iconCls: 'icon-add', handler: function () { $('#gridList').datagrid('endEdit', lastIndex); var rows = $('#gridList').datagrid('getRows'); //获取所有当前加载的数据行 var row = rows[rows.length - 1]; //不使用原行对象否则会产生关联 var newRow = cloneRow(row); newRow.ID = -1; newRow.NM = ''; $('#gridList').datagrid('appendRow', newRow); lastIndex = $('#gridList').datagrid('getRows').length - 1; $('#gridList').datagrid('selectRow', lastIndex); $('#gridList').datagrid('beginEdit', lastIndex); // var grid = document.getElementById('gridList'); // grid.scrollBottom = 0; $("#gridList").scrollBottom(0); } }, '-', { text: '删除', iconCls: 'icon-remove', handler: function () { var rows = $('#gridList').datagrid('getSelections'); // var checkedRow = $('#gridList').datagrid('getChecked'); if (rows.length <= 0) { alert('请选择要删除的记录!'); return false; } if (confirm('你确定要删除所选记录吗?')) { if (rows) { for (var i = 0; i < rows.length; i++) { var index = $('#gridList').datagrid('getRowIndex', rows[i]); $('#gridList').datagrid('deleteRow', index); } } var deleteRows = $('#gridList').datagrid('getChanges', 'deleted'); var saveArray = [null, deleteRows, null]; var saveArrayJson = JSON.stringify(saveArray); $.post(url, { Action: 'save', SaveArray: saveArrayJson }, function (data) { if (data) { loadGridData(); alert("删除成功!"); } else { alert("删除失败!"); } }); $('#gridList').datagrid('acceptChanges'); //在前端保存使操作不能回滚 } } }, '-', { text: '编辑', iconCls: 'icon-edit', handler: function () { if (editFlag) {//当验证未通过则上一个编辑行不能结束编辑,则editFlag=true $('#gridList').datagrid('selectRow', lastIndex); return; } var seleRow = $('#gridList').datagrid('getSelected'); if (seleRow) { var rowIndex = $('#gridList').datagrid('getRowIndex', seleRow); if (lastIndex != rowIndex) { $('#gridList').datagrid('endEdit', lastIndex); $('#gridList').datagrid('beginEdit', rowIndex); } lastIndex = rowIndex; } else { alert('请选择要编辑的记录!'); } } }, '-', { text: '保存', iconCls: 'icon-save', handler: function () { var rows = $('#gridList').datagrid('getRows'); for (var i = 0; i < rows.length; i++) { $('#gridList').datagrid('endEdit', i); //强制所有行结束编辑 } $('#gridList').datagrid('endEdit', lastIndex); //强制结束编辑 if (editFlag) {//当验证未通过则上一个编辑行不能结束编辑,则editFlag=true $('#gridList').datagrid('selectRow', lastIndex); return; } debugger; if (isRepeatNM(lastIndex)) { alert('已经存在同名记录!'); return false; } var insertRows = $('#gridList').datagrid('getChanges', 'inserted'); var deleteRows = $('#gridList').datagrid('getChanges', 'deleted'); var updateRows = $('#gridList').datagrid('getChanges', 'updated'); var saveArray = [insertRows, deleteRows, updateRows]; var saveArrayJson = JSON.stringify(saveArray); $.post(url, { Action: 'save', SaveArray: saveArrayJson }, function (data) { if (data) { alert("保存成功!"); loadGridData(); // window.location.reload(); } }); $('#gridList').datagrid('acceptChanges'); //在前端保存使操作不能回滚 } // }, '-', { // text: '撤销', // iconCls: 'icon-undo', // handler: function () { // $('#gridList').datagrid('rejectChanges'); // } }, '-', { text: '刷新', iconCls: 'icon-reload', handler: function () { loadGridData(); } }], onBeforeLoad: function () { $(this).datagrid('rejectChanges'); }, onClickRow: function (rowIndex) { //如非当前编辑行则结束编辑 if (lastIndex != rowIndex) { $('#gridList').datagrid('endEdit', lastIndex); } debugger; if (lastIndex && isRepeatNM(lastIndex)) { alert('已经存在同名记录!'); } }, onBeforeEdit: function (rowIndex, rowData) { editFlag = true; } , onAfterEdit: function (rowIndex, rowData, changes) { editFlag = false; } // , // onDblClickRow: function (rowIndex) { // //如并编辑行则使得编辑行结束编辑(此逻辑已在单击事件处理) // //双击选中复选框 // var row = $('#gridList').datagrid('getRows')[rowIndex]; // var checkedRow = $('#gridList').datagrid('getChecked'); // var isChecked = false; // for (var i = 0; i < checkedRow.length; i++) { // var index = $('#gridList').datagrid('getRowIndex', checkedRow[i]); // if (index == rowIndex) { // isChecked = true; // } // } // if (isChecked) { // $('#gridList').datagrid('uncheckRow', rowIndex); // } else { // $('#gridList').datagrid('checkRow', rowIndex); // } // } }); } //loadGridData方法begin function loadGridData(whereT) { //加载数据 var whereTStr = JSON.stringify(whereT); $.post(url, { Action: 'getGridData', Parameters: whereTStr }, function (data) { var json = $.parseJSON(data); $('#gridList').datagrid('loadData', json); //将数据绑定到datagrid }); } //loadGridData方法end //判断是否重名begin function isRepeatNM(lastIndex) { //如名称重复则alert并退回上条进行编辑 $('#gridList').datagrid('endEdit', lastIndex); var rows = $('#gridList').datagrid('getRows'); var lastRow = rows[lastIndex]; //此处lastRow有bug初次加载是lastRow为null var isRepeat = false; for (var i = 0; i < rows.length; i++) { if (rows[i].NM && i != lastIndex && rows[i].NM == rows[lastIndex].NM) { isRepeat = true; } } if (isRepeat) { $('#gridList').datagrid('selectRow', lastIndex); $('#gridList').datagrid('beginEdit', lastIndex); } return isRepeat; } //判断是否重名end //构造新行对象begin,不使用原型拷贝 function cloneRow(modelRow) { var newRow = {}; for (var p in modelRow) { var name = p; //属性名称 var value = modelRow[p]; //属性对应的值 newRow[name] = modelRow[p]; } return newRow; } //构造新行对象end
附件2:
datapattern.js
/** * 对Date的扩展,将 Date 转化为指定格式的String * 月(M)、日(d)、12小时(h)、24小时(H)、分(m)、秒(s)、周(E)、季度(q) 可以用 1-2 个占位符 * 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) * eg: * (new Date()).pattern("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 * (new Date()).pattern("yyyy-MM-dd E HH:mm:ss") ==> 2009-03-10 二 20:09:04 * (new Date()).pattern("yyyy-MM-dd EE hh:mm:ss") ==> 2009-03-10 周二 08:09:04 * (new Date()).pattern("yyyy-MM-dd EEE hh:mm:ss") ==> 2009-03-10 星期二 08:09:04 * (new Date()).pattern("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 */ Date.prototype.pattern=function(fmt) { var o = { "M+" : this.getMonth()+1, //月份 "d+" : this.getDate(), //日 "h+" : this.getHours()%12 == 0 ? 12 : this.getHours()%12, //小时 "H+" : this.getHours(), //小时 "m+" : this.getMinutes(), //分 "s+" : this.getSeconds(), //秒 "q+" : Math.floor((this.getMonth()+3)/3), //季度 "S" : this.getMilliseconds() //毫秒 }; var week = { "0" : "/u65e5", "1" : "/u4e00", "2" : "/u4e8c", "3" : "/u4e09", "4" : "/u56db", "5" : "/u4e94", "6" : "/u516d" }; if(/(y+)/.test(fmt)){ fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); } if(/(E+)/.test(fmt)){ fmt=fmt.replace(RegExp.$1, ((RegExp.$1.length>1) ? (RegExp.$1.length>2 ? "/u661f/u671f" : "/u5468") : "")+week[this.getDay()+""]); } for(var k in o){ if(new RegExp("("+ k +")").test(fmt)){ fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length))); } } return fmt; }