项目中需要一个可编辑表格控件,不能用一些js库,在网上搜索了一下,没有符合要求的,不是太简单就是没有和服务器通信的,自己花了一些时间写了符合条件的可编辑表格,在ie里测试正确,并把它放到我的常用js库中,特此分享一下,希望对一些朋友有帮助,有可以改进的地方大家一起提出和修改!!
BaseJs.EditTable = function(op) {
op = {
// 激活方法
active : op.active || "ondblclick",
table : op.table || {},
// 从第几行第几列开始可编辑
start : op.start || [2, 1],
// 到哪一行哪一列结束编辑
end : op.end || [],
// 表头对象
column : op.column || [],//
// 新增按钮
add : op.addAction || {},
// 保存按钮
save : op.saveOrUpdateAction || {},
// 删除按钮
del : op.delAction || {},
// id名
primaryKey : op.primaryKey,
// 合并的列数
mergeColumn : op.mergeColumn || []
};
// 修改后的记录集合
modified = [];
// 添加新记录
if (op.add.button)
op.add.button.onclick = function(e) {
var tr = op.table.insertRow(1);
function getfont(td, v) {
var font = document.createElement("font");
BaseJs.element.resetCss(td, {
color : 'red'
});
var textNode = document.createTextNode(v);
font.appendChild(textNode);
return font;
};
newdefault = {};
newdefault["newKey"] = BaseJs.random(1, 1, 9999999)[0];
for (var i = 0; i < op.column.length; i++) {
td = tr.insertCell(i);
tr.newid = newdefault["newKey"];
BaseJs.attr(td, "align", "center");
if (op.column[i].defaultValue) {
de = op.column[i].defaultValue;
newdefault[op.column[i].name] = de;
font = getfont(td, de);
td.appendChild(font);
} else {
font = getfont(td, "请修改数据");
newdefault[op.column[i].name] = "请修改数据";
td.appendChild(font);
}
}
op.start = [2, 1];
op.end = [2, op.column.length];
modified.push(newdefault);
BaseJs.EditTable.prototype.init(op);
if (op.add.callback)
op.add.callback.call(this, tr);
};
// 删除一条记录
if (op.del.button)
op.del.button.onclick = function(e) {
is = confirm("确认删除选择的记录吗?");
if(op.del.beforeCallback){
if(!op.del.beforeCallback.call(this)){
return;
};
}
delurl = (op.del.url.constructor == Function ? op.del
.url(op.del.button) : op.del.url);
if (!delurl) {
return;
}
if (is) {
BaseJs.Ajax.open({
url : delurl,
success : function(data) {
alert(data);
if (op.del.afterCallback)
op.del.afterCallback.call(this);
},
failure : function(data) {
alert(data);
}
});
}
}
// 保存修改
if (op.save.button)
op.save.button.onclick = function(e) {
is = confirm("是否确认保存当前修改?");
if(op.save.beforeCallback){
if(!op.save.beforeCallback.call(this,modified)){
return;
};
}
if (!is) {
return;
}
modifiedData = BaseJs.encode(modified);
saveurl = (op.save.url.constructor == Function
? op.save.url()
: op.save.url);
if (!saveurl)
return;
BaseJs.Ajax.open({
url : saveurl,
params : {
data : modifiedData
},
success : function(data, xml, opu, scope) {
// alert("data:" + xml.responseText);
BaseJs.foreach(modified, function(d) {
// 查找行去掉标记颜色
key = op.primaryKey;
id = BaseJs.isEmpty(d[key])
? d["newKey"]
: d[key];
BaseJs.foreach(op.table.rows, function(row) {
index = (BaseJs.isEmpty(row.id)
? row.newid
: row.id);
if (id == index) {
BaseJs.foreach(row.cells,
function(cell) {
BaseJs.element
.resetCss(
cell,
{
color : 'black'
})
}, this);
}
}, this)
}, scope);
alert(data);
(function() {
modified = [];
}).call(scope);
if (op.save.afterCallback)
op.save.afterCallback.call(this, modifiedData);
},
failuer : function(data, xml, op, scope) {
alert(data);
}
}, this);
};
// 初始化表格
this.init.call(this, op);
// 合并列
table = op.table;
merge = op.mergeColumn;
if (merge.length != 0)
this.merge(table, merge);
// 其它操作
}
BaseJs.EditTable.prototype = function() {
return {
// 计算开始结束序列号
getStartEnd : function(op, length, tds) {
var start = length * (op.start[0] - 1);
if (op.end.length == 0) {
nop = [0, length];
end = tds.length;
} else if (op.end.length == 1) {
nop = [0, op.end[0]]
end = tds.length
} else if (op.end.length == 2) {
nop = [op.end[0], op.end[1]];
end = length * (op.end[0]);
}
return [start, end, nop];
},
// 合并表格 merge=要合并的列数数组,如[0,1]第一列和第二列执行合并操作
merge : function(table, merge) {
for (i = 0; i < table.rows.length; i++) {
for (c = 0; c < table.rows[i].cells.length; c++) {
if (BaseJs.isContain(c, merge)) {
for (j = i + 1; j < table.rows.length; j++) {
var cell1 = table.rows[i].cells[c].innerHTML;
var cell2 = table.rows[j].cells[c].innerHTML;
if (cell1 == cell2) {
table.rows[j].cells[c].style.display = 'none';
table.rows[i].cells[c].rowSpan++;
} else
break;
}
}
}
}
},
init : function(op) {
var tds = BaseJs.getByTagName("td", op.table);
var length = op.column.length;
var se = this.getStartEnd(op, length, tds);
for (var i = se[0]; i < se[1]; i++) {
var cols = (i % length) + 1;
if (op.start[1] && se[2][1]
&& (cols < op.start[1] || cols > se[2][1])) {
continue;
}
(function() {
var td = tds[i];
var seq = i;
// 设置当前td序列号
var column = op.column;
tdEvent = function(e) {
// 得到目标对象
var target = (BaseJs.isIE ? e.srcElement : e.target);
// 计算当前td所处editorType值
var s = (seq) % length;
edittype = column[s].editorType;
// 得到原来的内容
var oldText = BaseJs.text(target);
// 清空原内容
BaseJs.empty(target);
// 设置默认类型为text
edittype = BaseJs.isEmpty(edittype) ? "text" : edittype;
this.html = "";
this.isLoad = true;
if (edittype == "text") {
this.html = "<input type='text' name='editText' id=seq value="
+ oldText + ">";
this.isLoad = true;
} else if (edittype == "textarea") {
cols = columns[s].cols ? columns[s].cols : 30;
rows = columns[s].rows ? columns[s].rows : 3;
this.html = "<textarea name='editText' id=seq value="
+ oldText
+ " cols="
+ cols
+ " rows="
+ rows + "></textarea>";
this.isLoad = true;
} else if (edittype == "date") {
// 格式化日期
var format = column[s].format;
format = (format ? format : "yyyy-MM-dd");
this.html = "<input type='text' name='editText' id=seq value="
+ oldText
+ " onclick=getDateString(this,oCalendarChs,'"
+ format + "')>";
this.isLoad = true;
} else if (edittype == "select") {
var me = this;
dataUrl = column[s].dataUrl.constructor == Function
? column[s].dataUrl(target)
: column[s].dataUrl;
if(column[s].data){
data = BaseJs.decode(column[s].data);
me.html = "<select name='editText'>";
for (var i = 0; i < data.length; i++) {
me.html += "<option value="
+ data[i].value + " display="+data[i].display+">"
+ data[i].display+"</option>";
}
me.html += "</select>";
}else{
// 加载远程数据
BaseJs.Ajax.open({
url : dataUrl,
success : function(data, res, op, me) {
data = BaseJs.decode(data);
me.html = "<select name='editText'>";
for (var i = 0; i < data.length; i++) {
me.html += "<option value="
+ data[i].value + " display="+data[i].display+">"
+ data[i].display+"</option>";
}
me.html += "</select>";
},
failure : function(data, res) {
alert(data);
me.isLoad = false;
},
isATM : false
}, this);
}
}
if (!this.isLoad) {
alert("加载数据有错,有稍后再试!");
return;
}
// 注入html
var newObj = BaseJs.element.htmlUtil.append(target,
this.html);
newObj = newObj.length ? newObj[0] : newObj;
BaseJs.element.resetCss(newObj, {
color : 'green'
});
newObj.focus();
newObj.click();
var action = (edittype == "date"
? "onchange"
: "onblur");
(function() {
curcolumn = column[s];
BaseJs.addEvent(newObj, action, function(e) {
var target = (BaseJs.isIE
? e.srcElement
: e.target);
// 得到对象
var s = target;
// 得到新值
var newText = s.value;
if(s.tagName.toLowerCase() == "select"){
BaseJs.foreach(s.options,function(op){
if (op.selected){
newText = {display:op.display,value:op.value};
}
})
}
// 检验所输入
if (curcolumn.validate) {
var is = curcolumn.validate(newText, s);
if (!is) {
s.focus();
return;
};
};
var parent = s.parentNode;
parents = parent;
do {
parents = parents.parentNode;
if (parents.tagName) {
tag = parents.tagName;
} else {
tag = "";
}
} while (tag.toLowerCase() != "tr");
// 保存修改
var name = curcolumn.name; // 得到当前字段名
var obj = {};
if (parents.newid) {
obj['newKey'] = parents.newid;
mod('newKey');
} else if (parents.id) {
obj[op.primaryKey] = parents.id;// // 保存关键id
mod(op.primaryKey);
}
function mod(key) {
obj[name] = newText.value?newText.value:newText; // 保存修改的字段
iscon = false; // 是否已保存该记录
index = 0;// 如何已修改的集合里有当前记录,保存其在modified中的索引号
for (var i = 0; i < modified.length; i++) {
mod = modified[i];
if (mod[key] == obj[key]) {
iscon = true;
index = i
};
}
if (!iscon) {
modified.push(obj);
} else {
modified[index][name] = newText.value?newText.value:newText;
}
}
// 删除编辑框
parent.removeChild(s);
// 创建文本
var font = document.createElement("font");
color = (oldText == newText ? "" : "red");
BaseJs.element.resetCss(parent, {
color : color
});
var textNode = document.createTextNode(newText.value?newText.display:newText);
font.appendChild(textNode);
// 插入文本
parent.appendChild(font);
// 待解决问题
// 9 表格修饰
});
})();
};
BaseJs.addEvent(td, op.active, tdEvent, this);
})();
}
}
};
}();
基本用法如下:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>内页面</title>
<script src="BaseJs.js" type="text/javascript"></script>
<script src="Calendar0.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
[align=center]交互编辑表格简单示例...[/align]
<form>
<input type="button" value="新增" id="add"/>
<input type="button" value="删除" id="delete"/>
<input type="button" value="保存修改" id="save"/>
<input type="hidden" id="mid"/>
<table width="80%" border="1" id="tab">
<tr align="center">
<td>年</th>
<td>com域名的数量</th>
<td>cn域名的数量</th>
<td>日期</th>
</tr>
<tr id="1" align="center">
<td>2003年</td>
<td>1000</td>
<td>2000</td>
<td>2003年12月份</td>
</tr>
<tr id="2" align="center">
<td>2004年</td>
<td>4000</td>
<td>5000</td>
<td>2004年12月份</td>
</tr>
<tr id="3" align="center">
<td>2005年</td>
<td>7000</td>
<td>8000</td>
<td>2005年12月份</td>
</tr>
</table>
</form>
<script type="text/javascript">
selectedRow = [];
//设置行选中状态
var trs = BaseJs.getByTagName("tr",BaseJs.$("tab"));
for (var i = 0; i < trs.length; i++) {
(function(){
var tr = trs[i];
trs[i].onclick = function(){
if (tr.selected){
tr.style.background = "#FAFCFE";
tr.selected = false;
for(i=0;i<selectedRow.length;i++){
if(selectedRow[i] == tr.id){
selectedRow.splice(i,1);
}
};
BaseJs.$("mid").value = selectedRow.join(",");
}else{
tr.style.background = '#B8CCF0';
tr.selected = true;
selectedRow.push(tr.id);
BaseJs.$("mid").value = selectedRow.join(",");
}
}
})();
}
table = new BaseJs.EditTable({
// 表对象
table : BaseJs.$("tab"),
// 从第几行第几列开始可编辑
start : [2, 1],
// 到哪一行哪一列结束编辑 不写默认所有,写一个参数代表列,行不限
end : [],
// 新增操作
addAction : {
// (button)执行操作的按钮,
button : BaseJs.$('add'),
// callback:执行操作后的回调函数,能够加入一些自定义操作
callback : function(tr) {
tr.onclick = function() {
var trs = BaseJs.getByTagName("tr",BaseJs.$("tab"));
for (var i = 0; i < trs.length; i++) {
trs[i].style.background = '#FAFCFE';
}
tr.style.background = '#B8CCF0';
}
}
},
// 保存新增或更新操作
saveOrUpdateAction : {
button : BaseJs.$('save'),
// 提交更新url,后台取参数data,为json字符串
url : 'saveOrUpdateActionUrl',
//返回true执行保存操作
beforeCallback:function(data){
alert("提交给后台url:saveOrUpdateActionUrl?data="+BaseJs.encode(data));
return false;
},
afterCallback : function(mo) {
alert("提交修改后的数据:"+mo);
//document.location.reload();
}
},
// 删除操作
delAction : {
button : BaseJs.$('delete'),
// 删除url 可用函数返回动态url
url : function() {
return 'delActionUrl&mid='
+ document.getElementById("mid").value;
},
//返回true执行删除操作
beforeCallback:function(){
alert("提交给后台url:delActionUrl?sids="+document.getElementById("mid").value);
return false;
},
afterCallback : function() {
document.location.reload();
}
},
// id名(记录的id值需要保存在tr.id上)
primaryKey : 'id',
// 要全并的列数集合 [0]代表第一列要执行合并操作,[0,1]代表1,2列有合并操作
mergeColumn : [],
// 列描述对象 ,包含一个数组,数组中每一个对象说明一个列编辑对象和相关处理
column : [
{
name : 'year',
// 选择型
editorType : 'select',
// 加载select数据url,返回json数据,格式应为:[{display:'',value:''},{display:'',value:''}]
dataUrl : 'WaterQualityAction?method=AjaxSelect¶=LEVEL',
//可以动态返回
//dataUrl : function(me){
// return 'WaterQualityAction?method=AjaxSelect¶=LEVEL';
//},
//本地数据 有此选项时dataUrl无效
data:"[{display:'2005年',value:'2005'},{display:'2004年',value:'2004'},{display:'2003年',value:'2003'},{display:'2002年',value:'2002'},{display:'2001年',value:'2001'}]",
// 新增默认值,不写使用默认
defaultValue : '2008年',
// 检验输入数据正确性,返回true通过验证
validate : function(v, obj) {
alert("现在检验输入数据合法性!");
return true;
}
},
{
name : 'com',
editorType : 'text',
defaultValue : '请输入',
validate : function(v, obj) {
if (!/^[0-9]+$/.test(v)){alert("必须是数字");return false};
return true;
}
},
{
name : 'cn',
editorType : 'text',
defaultValue : '请输入',
validate : function(v, obj) {
if (!/^[0-9]+$/.test(v)){alert("必须是数字");return false};
return true;
}
}, {
name : 'date_month',
// 日期型
editorType : 'date',
// 格式化日期样式,默认yyyy-MM
format : 'yyyy年MM月份',
//自定义默认值
defaultValue : BaseJs.Utils.format
.date(new Date(), 'yyyy年MM月份')
}]
});
</script>
</body>
</html>
源代码在下载的文件里,有什么不合理或错误的地方请大家指出,一起学习!!