<html> <Head> <style type = "text/css"> .grid {border: 1px solid #808080; Расхождение границы: 0; Ширина: 500px; Border-Collapse: коллапс} .grid th, .grid td {border: 0; Text-align: center;} .grid tr {height: 25px; line-hight: 25px;} .grid tr.odd {founale:#d0d0d0} .grid .btn {width: 80px; Text-align: center} </style> <script type = "text/javascript"> (function () {// var util = {Next: function Next (ele) {if (ele) {var n = ele.nextibling; if (n && n.nodetype === 1) {return n;} return (n); JSON! == "Undefined") {return json.parse (str); Array.prototype.slice.call (obj, 0); «Undefice") {Result.push (Target); offset (ele) {var result = {top: 0, слева: 0}; (ele.style.top || "0"). заменить (/[^/d]+$/, "")); result.left = number (ele.offsetleft || (ele.style.left || "0"). Заменить (/[^/d]+$/, "")); if (ele.parentnode) {var r = offset (ele.parentnode); result.top += r.top; result.left += r.left; } return Result; }}; // 事件处理 var event = {on: function (eventType, fn) {var element = this; if (this.addeventlistener) {this.addeventListener (EventType, fn, false); } else if (this.attachevent) {// 将事件缓冲到该标签上, 已解决 это 指向 指向 window (现 fn 内 指向 指向 element) 和移除匿名事件问题 var _eventref = '_'+eventType+'EventRef'; if (! element [_eventref]) {element [_eventref] = []; } var _eventrefs = element [_eventref]; var index; for (index in _eventrefs) {if (_eventrefs [index] ['realfn'] == fn) {return; }} var nestfn = function () {fn.apply (element, arguments); }; element [_eventref] .push ({'realfn': fn, 'nestfn': nestfn}); element.attachevent ('on'+eventtype, nestfn); }}, удалить: function (eventType, fn) {var element = this; if (this.removeeventlistener) {this.removeeventListener (eventType, fn, false); } else if (this.detachevent) {var _eventref = '_'+eventType+'EventRef'; if (! element [_eventref]) {element [_eventref] = []; } var _eventrefs = element [_eventref] var index; var nestfn; for (index in _eventrefs) {if (_eventrefs [index] ['realfn'] == fn) {nestfn = _eventrefs [index] ['nestfn']; if (index == _ eventRefs.length-1) {element [_eventref] = _ eventRefs.slice (0, index); } else {element [_eventref] = _ eventrefs.slice (0, index) .concat (_eventrefs.slice (index+1, _eventrefs.length-1)); } перерыв; }} if (nestfn) {element.detachevent ('on'+eventtype, nestfn); }}}}; // extend (function () {// 删除数组中指定下标出的元素 array.prototype.remove = function (index) {var o = this [index]; if (typeof o! == "undefined") {if (index == 0) {this.shift ();} иначе if (index === this.length -1) {this.pop (); это. } for (var i = 0; i <this.length; i ++) {if (typeof this [i]! == "Undefined") {fn.call (this [i], i); Это. {}; for (var k в этом .__ data) {if (k && typeof this .__ Data [k]! == "Undefined") {fn.call (this .__ Data [k], index ++); }}}, toarray: function () {var arr = []; это. возврат Arr; }}; }) (); // var grid = this.grid = function (таблица, параметры) {grid.prototype._init.call (это, таблица, опции); } grid.prototype = {_init: function (таблица, параметры) {if (typeof table === "undefined" ||! Таблица) {Throw "таблица не определена или нулевая"; } if (table.nodeType! == 1 ||!/^Таблица $/i.test (table.tagname)) {Throw 'Таблица должна быть «таблица». } table.guid = ++ grid.guid; это .__ cache = {}; var self = это; var Header = this .__ Cache ["Header"] = LoadHeader (); // Заголовок этого .__ root = header.parentNode; var templaterow = this .__ Cache ["template"] = loadtemplate (); // 模板行 this .__ Cache ["dataFormat"] = LoadDataFormat (); // 数据模板 This .__ Cache ["DataRows"] = new Collection (); // 数据行 This .____ Cache [CustomCache "] = new Collection (); // e. это .__ SaveContainer = createSaveButton (); // 保存按钮 This .__ Cache ["CommandHandles"] = {// Командовые ручные ручной работы: function () {var Rowindex = this.getAttribute ("index"); self.removerow.apply (self, [rowindex]); }, newline: function () {self.newline (); }}; это .__ regcommand = function (commandMAme, row) {// 注册 Команда if (row) {var arg = row.getAttribute ("index"); this.setattribute ("index", arg || false); } this.comMandName = CommandName; Event.remove.call (this, "click", exec); Event.on.call (это, «клик», exec); } this .__ RemoverowCallback = function () {// 改变行的背景样式 var row = this .__ Cache ["DataRows"]; var CustomCache = this .__ Cache ["CustomCache"]; var arr = row.toarray (), dataarr = []; var rowindex, row, data; rows.clear (); arr.each (function (i) {rowindex = this.getattribute ("index"); data = customcache.get (rowindex); dataarr.push (data); this.setattribut if (! // sodd/s | /sodd$/g.test (this.classname)) {this.classname = (this.classname || "") + "add"; this.classname.replace (// sodd/s |/sodd $/g, ""); CustomCache.Clear (); dataarr.each (function () {customCache.add (this);}); } // 事件处理 Опции = Параметры || {}; this.ondatabinding = options.ondatabinding || это. Определение; this.onrowbinding = options.onrowbinding || это. onrowbinding; this.OnRowbInd = options.Onrowbided || это. function LoadHeader () {var tr = table.firstchild; if (tr && tr.nodeType! = 1) {tr = util.next (tr); } if (!/tr/i.test (tr.tagname)) {// 如果第一个元素不是 tr , 则浏览器支持 tbody tr = tr.firstchild; if (tr.nodeType! = 1) {tr = util.next (tr); }} return tr; } function loadTemplate () {tr = util.next (header); // 获取模板行 return tr; } function LoadDataFormat () {var nodes = templaterow.childnodes, ele, data, result = {}, attr; узлы = util.parsearray (узлы); nodes.each (function (i) {ele = this; if (ele && ele.nodetype == 1) {attr = ele.data || ele.getattribute ("data"); if (attr) {data = util.parsejson (attr); ele.field = data.field; relafe [ele.field] = data;}}}}); результат возврата; } function createSaveButton () {var div = document.createElement ("div"); div.style.position = "Absolute"; div.style.display = "нет"; div.style.width = "auto"; var btn = document.createElement ("кнопка"); btn.innerhtml = btn.innertext = btn.textcontent = btn.value = "Сохранить"; try {btn.type = "button"; } catch (e) {btn.setattribute ("type", "button"); } div.appendchild (btn); var btncancel = document.createElement («кнопка»); btncancel.innerhtml = btncancel.innertext = btncancel.textcontent = btncancel.value = "cancel"; try {btncancel.type = "кнопка"; } catch (e) {btncancel.setattribute ("type", "button"); } div.appendChild (btncancel); document.body.appendchild (div); Event.on.call (btn, "click", function () {self.save ();}); Event.on.call (btncancel, "click", function () {div.style.display = "none"; if (self .__ editrow) {self .__ editrow.parentnode.removechild (self .__ editrow); self .__ editrow = null;}}); вернуть див; } function exec () {if (self .__ editrow) {// 如果当前处于编辑模式 , 则禁用所有 return return; } var CommandMAme = this.comMandName; var handler = self .__ Cache ["CommandHandles"] [CommandMAme]; if (Handler) {handler.call (this); }} // 去除模板行 templaterow.parentnode.removechild (Templaterow); // 处理表格中的 Команда 事件 var elements = header.getElementsbytagname ("*"); elements = util.parsearray (элементы); elements.each (function () {if (this.nodeType === 1) {var CommandMAme = this.command || this.getAttribute ("command"); if (commandMame) {self .__ regcommand.call (this, commandMame, header);}}}); }, // Bungding Bind: function (data) {this.clear (); if (data && data.length> 0) {var self = this; data.each (function () {self.append (this);}); }}, // 清理表 , 删除所以除 заголовок 以外的数据行 clear: function () {var row = this .__ Cache ["dataRows"], row; row.each (function () {row = this; if (row) {row.parentnode.removechild (row);}}); row.clear (); // 清理 Rows}, // 删除指定的行 Removerow: function (rowindex) {var Rows = this .__ Cache ["DataRows"]; var row = row.get (rowindex); if (row) {var data = this .__ cache ["customcache"] [rowindex]; row.parentnode.removechild (row); Rows.remove (rowindex); // 通知用户数据行被移除 if (util.isfunction (this.onrowremoved)) {this.onrowremoved (data, row); }} this .__ RemoverowCallback (); }, // 添加 行 Приложение: function (data) {if (! Data) {return; } var template = this .__ Cache ["Template"]; var Rows = this .__ Cache ["DataRows"]; var rowindex = row.length; var tr = template.clonenode (); var CustomCache = this .__ Cache ["CustomCache"]; customcache.add (data); // 将数据行添加到 таблица это .__ root.appendchild (tr); var self = это; var td, // 数据单元格 DataFormat, // 数据格式化器 value; // 单元格中的给定的数据 tr.setattribute ("index", rowindex.tostring ()); // 更改样式 if (rowindex % 2 == 1) {tr.classname = (tr.classname || "") + "add"; } // 通知 行数据绑定开始 if (util.isfunction (this.onrowbinding)) {this.onrowbinding (rowindex, tr); } var templatetd = template.firstchild; while (templatetd) {td = templatetd.clonenode (true); Tr.AppendChild (TD); if (td.nodetype == 1 && templatetd.field) {dataFormat = this .__ Cache ["dataFormat"] [TemplatetD.Field]; Td.RemoVeatTribute («Данные»); Td.field = Templatetd.field; value = data [dataformat.field]; // 通知单元格数据绑定事件 value = this.ondatabinding (dataformat.field, value, td, data); if (value! == false) {// 如果返回 false , 则不用做赋值操作 switch (dataformat.render) {case "innerhtml": td.innerhtml = typeof value == "не определен" || Значение == NULL? "" : ценить; перерыв; case "InnerText": по умолчанию: td.innertext = td.textContent = typeof value == "не определен" || Значение == NULL? "" : ценить; перерыв; }}} templatetd = templatetd.nextibling; } row.Add (tr); // 处理 Команда var elements = tr.getElementsbytagname ("*"), ele, attr; elements = util.parsearray (элементы); elements.each (function () {ele = this; if (ele.nodetype == 1 && (ele.command || ele.getattribute ("command"))) {attr = ele.command || ele.getattribute ("command"); Self .__ regcommand.call (el, attr, tr); // 通知 行数据绑定完成 if (util.isfunction (this.onrowbided)) {this.onrowbided (rowindex, tr); }}, // 手动产生新的输入行 newline: function () {if (this .__ editrow) {// 如果当前有存在编辑行 , 则直接返回 , 每次最多限制编辑一行数据 return; } var template = this .__ Cache ["Template"]; var row = this .__ editrow = template.clonenode (false); var templatetd = template.firstchild; var textareAlist = []; while (templatetd) {td = templatetd.clonenode (true); row.appendchild (TD); if (td.nodetype == 1) {if (templatetd.field) {td.field = templatetd.field; td.innerhtml = ""; var DataFormat = this .__ Cache ["DataFormat"] [TemplatetD.Field]; var textARea = null; if (dataformat.render == "innerhtml") {textarea = document.createElement ("textarea"); } else {textARea = document.createElement ("input"); TextAREA.Type = "text"; } textarea.style.display = "none"; Td.appendchild (Textarea); TextareAlist.push (Textarea); }} templatetd = templatetd.nextibling; } // 将数据行添加到 таблица это .__ root.appendchild (row); var height = row.offsetheight, width = row.offsetwidth, offset = util.offset (row); TextARAREAL.Epect (function () {this.style.height = (0,8 * высота) + "px"; this.style.width = (0,8 * this.parentnode.offsetwidth) + "px"; this.style.display = "";}); var Left = offset.left + ширина + 5; var top = offset.top; this.__savecontainer.style.top = top + "px"; это .__ SaveContainer.Style.left = Left + "px"; это .__ savecontainer.style.height = this .__ SaveContainer.style.lineHeight = height + "px"; это .__ savecontainer.style.display = "block"; }, // 保存手动产生的数据行数据 save: function () {if (! This .__ editrow) {return; } var row = this .__ editrow; var td = row.firstchild; var data = {}; while (td) {if (td.nodeType === 1 && td.field) {var dataFormat = this .__ Cache ["dataFormat"] [td.field]; var textARea = null; if (dataformat.render == "innerhtml") {textarea = td.getelementsbytagname ("textarea") [0]; } else {textARea = td.getElementsbytagname ("input") [0]; } value = textARea.value; switch (dataFormat.datatype) {case "number": value = util.trim (value); value = number (value.length == 0? 0: value); перерыв; по умолчанию: перерыв; } data [td.field] = value; } td = td.nextibling; } this .__ editrow.parentnode.removechild (this .__ editrow); это .__ editrow = null; это .__ savecontainer.style.display = "none"; // 通知用户正在保存数据 if (util.isfunction (this.Onsaving)) {this.Onsaving (data); } this.append (data); }, getRowData: function (rowindex) {return this .__ Cache ["customcache"]. get (rowindex); }, // 数据绑定到指定 Cell 时的事件 OnDataBinding: function (поле, значение, ячейка, данные) {return value; }, // 当数据行绑定开始时的事件 OnRowBinding: function (RowIndex, Row) {}, // 当数据行绑定完成时的事件 //@param Row {dom lement Tr} onRowbInd: function (rowIndex, row) {}, // 当编辑的数据被保存时的事件 OnSaving: function (data) {}, // 当数据行被移除时的通知事件 onRowRemoved: function (data, row) {}}; grid.guid = 0; }) (); </script> </head> <body> <table id = "table_demo"> <tr> <th> id </th> <Th> name </th> <Th> Decpription </th> <Th> <tood Type = "command =" newline "> Новая линия </button> </th> </tr> <tr> <td data = '{"field": "id", "datatype": "number", "render": "innertext"}'> 1 </td> <td data = '{"field": "name", "datatype": "string", "рендеринг": "innertext"}'> horkservice </td> data = '{"field": "description", "dataType": "string", "render": "innerHtml"}'> workingservice </td> <td> <button Type = "command =" Removerow "> Delete </button> </td> </tr> </table> <script =" document.getElementbyId ("table_demo"); var g = new Grid (таблица, {ondatabinding: function (field, value) {return value;}, onRowbInd: function (rowIndex, row) {}}); g.bind ([{id: 0, имя: "kilin"}, {id: 1, имя: "kilin1"}, {id: 2, name: "kilin2"}, {id: 3, name: "kilin3"}]); </script> </body> </html>