原创-javascript服务器交互型可编辑表格

   项目中需要一个可编辑表格控件,不能用一些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&para=LEVEL',
				//可以动态返回
				//dataUrl : function(me){
				//  return  'WaterQualityAction?method=AjaxSelect&para=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>


源代码在下载的文件里,有什么不合理或错误的地方请大家指出,一起学习!!

你可能感兴趣的:(JavaScript,C++,c,Ajax,C#)