Электронные таблицы на JS
Здравствуйте!
Хочу сделать нечто вроде экселевской таблицы на JavaScript. Я сделал её, но работает медленно. Если взять таблицу размером (800х14) то её загрузка в IE требует 29 секунд. Я недоволен. Не хочется изобретать велосипед, может ктото делал такую вещь? Посоветуйте что нибудь. Могу скинуть свой код, там 205 строк. |
скинь, мне интересно.
У меня генерация таблицы 800*14 в ФФ2 занимает 2100миллисекунды (визуально 3). |
Сам не реализовывал, поэтому по слухам: большие таблицы сильно тормозят (в ИЕ?). Вариант решения: разбивать на много маленьких таблиц, следующих друг за другом.
|
Большик таблицы просто жесть как тормозят в ИЕ, но также они тормозят в Сафари (но меньше), потом идёт ФФ, и почти не тормозят в Опере (но в опере вылазит куча других проблем)...
|
вот мой код
/* SpreadSheet.js */ Array.prototype.search = function(search){ var i=0;while(this[i++]!=search && i<this.length); return this[i-1]!=search?false:i-1; }; /* ЯЧЕЙКА ТАБЛИЦИ */ function cell(){ this.r = 0; this.c = 0; this.parent = null; this.value = ''; this.borderColor = '#7F9DB9'; this.borderWidth = '1'; this.defaultStyle = function(){ this.borderColor = '#7F9DB9'; this.borderWidth = '1'; }; this.activeStyle = function(){ this.borderColor = '#000000'; this.borderWidth = '3'; }; this.setAutoCompleter = function(url){ /*var td = this.findTableCell(this.r,this.c); var input = td.getElementsByTagName('INPUT')[0]; var acDiv = document.createElement("DIV"); acDiv.className = 'ac'; td.appendChild(acDiv); this.AutoCompleter = new AutoCompleter(acDiv,input,url); _onkeydown = input.onkeydown; input.onkeydown = function(e){ if('block' == acDiv.style.display){} else {_onkeydown();} };*/ }; this.findTableCell = function(r,c){ var t = this.parent._obj.getElementsByTagName('TABLE'); return t[t.length-1].getElementsByTagName('TR')[this.r-1].getElementsByTagName('TD')[this.c-1]; }; } /* ТАБЛИЦА */ function sheet(obj){ return { row:1, col:1, cells:[], // хеш массив ячеек _obj:obj, cell:function(r,c){ var rCount=0,cCount=0; while(this.cells.length < r){ this.cells.push([]); rCount = this.cells.length - 1; while(this.cells[rCount].length < c){ this.cells[rCount].push(new cell()); cCount = this.cells[rCount].length - 1; this.cells[rCount][cCount].r = rCount+1; this.cells[rCount][cCount].c = cCount+1; this.cells[rCount][cCount].parent = this; } } return this.cells[r-1][c-1]; }, moveTo:function(r,c){ if(r<1 || c<1 || r>this.cells.length || c>this.cells[0].length) return; with(this){ cell(this.row,this.col).defaultStyle(); cell(r,c).activeStyle(); updateCell(this.row,this.col); updateCell(r,c); row=r; col=c; } }, updateCell:function(r,c){ var t = obj.getElementsByTagName('TABLE'); row = t[t.length-1].getElementsByTagName('TR')[r-1]; cell = row.cells[c-1]; input = cell.getElementsByTagName('INPUT')[0]; input.style.borderWidth = this.cell(r,c).borderWidth; input.style.borderColor = this.cell(r,c).borderColor; if(''!=input.value && input.value!=this.cell(r,c).value) this.cell(r,c).value = input.value; input.value = this.cell(r,c).value; input.focus(); }, show:function(){ t = []; currenCell = {}; t.push('<div></div><br><div><table border="0">'); rCount = this.cells.length; cCount = this.cells[0].length; var tt= this var OnKeyDown = function(e){ switch( keyCode(e) ){ case 37: tt.moveTo(tt.row,tt.col-1); break; // move left case 38: tt.moveTo(tt.row-1,tt.col); break; // move up case 39: tt.moveTo(tt.row,tt.col+1); break; // move right case 40: tt.moveTo(tt.row+1,tt.col); break; // move down } }; for(r=0; r<rCount; r++){ t.push('<tr>'); for(c=0; c<cCount; c++){ currenCell = this.cells[r][c]; t.push('<td><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="' + currenCell.value + '"></td>'); } t.push('</tr>'); } t.push('</table></div>'); obj.innerHTML = t.join("\n"); var inputs = obj.getElementsByTagName('INPUT'); var inpCount = inputs.length; for(i=0;i<inpCount;i++){ inputs[i].onclick= function(){ c = this.parentNode.cellIndex +1; r = this.parentNode.parentNode.rowIndex +1; tt.moveTo(r,c); }; inputs[i].onkeydown = OnKeyDown; }/**/ window.onunload = function(){tt.cleanUp(tt)}; }, addHeaders:function(labelsList){ // labelList format: {name1:isSortable,name2:isSortable} var labels = [],h = []; for(key in labelsList) labels.push({name:key,isSortable:labelsList[key]}); var rCount = this.cells[0].length; var t = this._obj.getElementsByTagName('DIV')[0]; var tw = this._obj.getElementsByTagName('TABLE')[0].clientWidth; var dt = this._obj.getElementsByTagName('TABLE')[0].getElementsByTagName('TR'); h.push('<table cellspacing="0" cellpadding="0"><tr>'); var v,options=[]; for(i=0;i<rCount;i++){ h.push('<td>'); if(i<labels.length){ if(labels[i].isSortable){ h.push('<select style="background:#99CCFF;">'); h.push('<option>'+labels[i].name+'</option>'); for(j=0;j<this.cells.length;j++){ if(false===options.search(this.cells[j][i].value) && ''!=this.cells[j][i].value){ options.push(this.cells[j][i].value); } } for(j=0;j<options.length;j++) h.push('<option value="'+options[j]+'">'+options[j]+'</option>'); options=[]; h.push('</select>'); }else h.push(labels[i].name); }else{h.push(' ')} h.push('</td>'); } h.push('</tr></table>'); t.innerHTML = h.join("\n"); h = this._obj.getElementsByTagName('TABLE')[0].getElementsByTagName('TR')[0].getElementsByTagName('TD'); t = this._obj.getElementsByTagName('TABLE')[1].getElementsByTagName('TR')[0].getElementsByTagName('TD'); this._obj.getElementsByTagName('TABLE')[1].style.width = this._obj.getElementsByTagName('TABLE')[0].clientWidth; for(i=0;i<h.length;i++) t[i].style.width = h[i].clientWidth; }, getValueList:function(collIndex){ var list = [],v; for(i=0;i<this.cells.length;i++){ if(!list.toString().match(this.cells[i][collIndex].value)){ v = this.cells[i][collIndex].value; list.push('<option value="' + v +'">' + v + '</option>'); } } return list.join(''); }, cleanUp:function(tt){ // избегаем утечку памяти в Microsoft Internet Explorer for(i=0;i<tt.cells.length;i++){ for(j=0;j<tt.cells[0].length;j++){ tt.cells[i][j].parent=null; if(tt.cells[i][j].AutoCompleter){ tt.cells[i][j].AutoCompleter = null; } } } var inp = document.getElementsByTagName('INPUT'); for(l=0;l<inp.length;l++){ inp[l].onclick = null; inp[l].onkeydown = null; } } }; } function keyCode(e){ if (window.event) return window.event.keyCode; else if (e) return e.which; } так его запускать <html> <head> <!--<link type="text/css" href="style.css" rel="stylesheet">--> <!--<script type="text/javascript" src="java.js"></script>--> </head> <body> <!-- ЭЛЕКТРОННАЯ ТАБЛИЦА--> <script type="text/javascript" src="SpreadSheet.js"></script> <div id="SpreadSheet" align="center"> </div> <script> var b = new Date(); var s = new sheet(document.getElementById('SpreadSheet')); s.cell(800,14); s.show(); // s.cell(1,1).value = '11'; //s.updateCell(1,1); //s.moveTo(1,1); //s.cell(305,14); //s.cell(1,1).setAutoCompleter('../helpdesk/trunk/ajaxDispecher.php?name=street'); s.addHeaders({'Адрес установки':1,'Дом':1,'Под':1,'Switch':1,'IP адрес':1,'serial sw':1,'модуль':1,'1 модуль':1,'2 модуль':1,'Заказан':1,'Подготовлен':1,'Выдан':1,'Установлен':1,'Пометки':1}); var e = new Date(); alert((e.getTime() - b.getTime())/1000); </script> <!-- КОНЕЦ ЭЛЕКТРОННОЙ ТАБЛИЦИ--> </body> </html> |
жесть... updateCell тормозная функция 117 милисекунд выполняется... с учётом того, что на одно передвижение она вызывается 2 раза получаются визуальные тормоза...
После профилировки обнаружил, что addHeaders занимает больше времени при создании таблицы, чем show :) Оптимизировать и оптимизировать... Советы: - избавиться от всех getElementsByTagName (снести в инициализацию, одни раз их сделать, записать в свойства объекта "Электронная Таблица") - не использовать .push, а использовать [index] = ... - ты при генерации таблицы делаешь t.innerHTML = h.join("\n"); Я не помещаю строки в массив, а формирую сразу строку. В итоге получается быстрее, чем у тебя (хоть тесты и говорят, что в массив быстрее)... |
ZoNT, спасибо за советы. Как думаешь если оптимизировать можно в 2 секунды уложиться ? Или может лучше сгенерировать таблицу на php, а к ней уже обработчики событий прикрутить? Или может лучше вообще отказаться от этой затеи и написать на java аплет? Если у тебя есть можеш свой вариант скинуть ?
|
Немного ускорил.
Но структура бредовая... 1) Зачем в каждую ячейку пихать инпут? 2) Зачем на каждый инпут(ячейку) вешать обработчик событий? /* SpreadSheet.js */ Array.prototype.search = function(search){ for(var i=0,l=this.length;i<l;i++)if(this[i]==search)return i; return false; } /* ЯЧЕЙКА ТАБЛИЦИ */ function cell(){ this.r = 0; this.c = 0; this.parent = null; this.value = ''; this.borderColor = '#7F9DB9'; this.borderWidth = '1'; this.defaultStyle = function(){ this.borderColor = '#7F9DB9'; this.borderWidth = '1'; } this.activeStyle = function(){ this.borderColor = '#000000'; this.borderWidth = '3'; } this.setAutoCompleter = function(url){} this.findTableCell = function(r,c){ var t = this.parent._obj.getElementsByTagName('TABLE'); return t[t.length-1].getElementsByTagName('TR')[this.r-1].getElementsByTagName('TD')[this.c-1]; } } /* ТАБЛИЦА */ function sheet(obj){ return { row:1, col:1, cells:[], // хеш массив ячеек _obj:obj, cell:function(r,c){ var rCount=0,cCount=0; while(this.cells.length < r){ this.cells.push([]); rCount = this.cells.length - 1; while(this.cells[rCount].length < c){ this.cells[rCount].push(new cell()); cCount = this.cells[rCount].length - 1; this.cells[rCount][cCount].r = rCount+1; this.cells[rCount][cCount].c = cCount+1; this.cells[rCount][cCount].parent = this; } } return this.cells[r-1][c-1]; }, moveTo:function(r,c){ if(r<1 || c<1 || r>this.cells.length || c>this.cells[0].length) return; with(this){ cell(this.row,this.col).defaultStyle(); cell(r,c).activeStyle(); updateCell(this.row,this.col); updateCell(r,c); row=r; col=c; } }, updateCell:function(r,c){ var input = this.Table.rows[r-1].cells[c-1].firstChild; var C = this.cell(r,c); input.style.borderWidth = C.borderWidth; input.style.borderColor = C.borderColor; if(''!=input.value && input.value!=C.value) C.value = input.value; input.value = C.value; input.focus(); }, show:function(){ var t=[],i=0,currenCell; t[i++] = '<table border="0">'; var rCount = this.cells.length; var cCount = this.cells[0].length; var tt = this; var OnKeyDown = function(e){ e=e||event; switch(e.keyCode||e.charCode){ case 37: tt.moveTo(tt.row,tt.col-1); break; // move left case 38: tt.moveTo(tt.row-1,tt.col); break; // move up case 39: tt.moveTo(tt.row,tt.col+1); break; // move right case 40: tt.moveTo(tt.row+1,tt.col); break; // move down } } t[i++] = '<tr>'; var h = this.Header.rows[0]; for(var c=0; c<cCount; c++){ currenCell = this.cells[0][c]; t[i++] = '<td style="width:'+h.cells[c].offsetWidth+'px;"><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="' + currenCell.value + '"></td>'; } t[i++] = '</tr>'; for(var r=1; r<rCount; r++){ t[i++] = '<tr>'; for(var c=0; c<cCount; c++){ currenCell = this.cells[r][c]; t[i++] = '<td><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="' + currenCell.value + '"></td>'; } t[i++] = '</tr>'; } t[i++] = '</table>'; this._obj.lastChild.innerHTML = t.join(""); this.Table = this._obj.lastChild.firstChild; this.Table.style.width = this.Header.offsetWidth; var inputs = this._obj.getElementsByTagName('INPUT'); var inpCount = inputs.length; for(var i=0;i<inpCount;i++){ inputs[i].onclick= function(){ c = this.parentNode.cellIndex +1; r = this.parentNode.parentNode.rowIndex +1; tt.moveTo(r,c); }; inputs[i].onkeydown = OnKeyDown; } window.onunload = function(){tt.cleanUp(tt)}; }, addHeaders:function(labelsList){ // labelList format: {name1:isSortable,name2:isSortable} var labels = [],h = [],k=0; for(var key in labelsList) labels.push({name:key,isSortable:labelsList[key]}); var rCount = this.cells[0].length; var cCount = this.cells.length; var t = this._obj; h[k++] = '<div><table cellspacing="0" cellpadding="0"><tr>'; for(var i=0;i<rCount;i++){ h[k++] = '<td>'; if(i<labels.length){ if(labels[i].isSortable){ h[k++] = '<select style="background:#99CCFF;"><option>'+labels[i].name+'</option>'; var options=[]; for(var j=0;j<cCount;j++){ var v = this.cells[j][i].value; if(false===options.search(v) && ''!=v){ options.push(v); h[k++] = '<option value="'+v+'">'+v+'</option>'; } } h[k++] = '</select>'; } else h[k++] = labels[i].name; } else h[k++] = ' '; h[k++] = '</td>'; } h[k++] = '</tr></table></div><br><div></div>'; t.innerHTML = h.join(""); this.Header = t.firstChild.firstChild; }, getValueList:function(collIndex){ var list = [],v; for(var i=0;i<this.cells.length;i++){ if(!list.toString().match(this.cells[i][collIndex].value)){ v = this.cells[i][collIndex].value; list.push('<option value="' + v +'">' + v + '</option>'); } } return list.join(''); }, cleanUp:function(tt){ // избегаем утечку памяти в Microsoft Internet Explorer for(var i=0;i<tt.cells.length;i++){ for(var j=0;j<tt.cells[0].length;j++){ tt.cells[i][j].parent=null; if(tt.cells[i][j].AutoCompleter){ tt.cells[i][j].AutoCompleter = null; } } } var inp = document.getElementsByTagName('INPUT'); for(var l=0;l<inp.length;l++){ inp[l].onclick = inp[l].onkeydown = null; } } }; } Вызов addHeaders в html должен идти ПЕРЕД show()!!! |
Цитата:
Если на пхп таблица сгенерится быстрее, то это конечно лучший вариант... |
Ага, учтя твои замечания думаю сделать так:
1 таблицу генерировать на пхп 2 сделать один input который будет бегать по ячейкам таблицы и менять значения в них. 3 на input повесить все события, и убрать объект cell - поидеи он тогда вообще не нужен будет |
смотри:
/* SpreadSheet.js */ Array.prototype.search = function(search){ for(var i=0,l=this.length;i<l;i++)if(this[i]==search)return i; return false; } /* ЯЧЕЙКА ТАБЛИЦИ */ function cell(){ this.r = 0; this.c = 0; this.parent = null; this.value = ''; this.borderColor = '#7F9DB9'; this.borderWidth = '1'; this.defaultStyle = function(){ this.borderColor = '#7F9DB9'; this.borderWidth = '1'; } this.activeStyle = function(){ this.borderColor = '#000000'; this.borderWidth = '3'; } this.setAutoCompleter = function(url){} this.findTableCell = function(r,c){ var t = this.parent._obj.getElementsByTagName('TABLE'); return t[t.length-1].getElementsByTagName('TR')[this.r-1].getElementsByTagName('TD')[this.c-1]; } } /* ТАБЛИЦА */ function sheet(obj){ return { row:1, col:1, cells:[], // хеш массив ячеек _obj:obj, cell:function(r,c){ var rCount=0,cCount=0; while(this.cells.length < r){ this.cells.push([]); rCount = this.cells.length - 1; while(this.cells[rCount].length < c){ this.cells[rCount].push(new cell()); cCount = this.cells[rCount].length - 1; this.cells[rCount][cCount].r = rCount+1; this.cells[rCount][cCount].c = cCount+1; this.cells[rCount][cCount].parent = this; } } return this.cells[r-1][c-1]; }, moveTo:function(r,c){ var t = this; if(r<1 || c<1 || r>t.cells.length || c>t.cells[0].length) return; t.cell(t.row,t.col).defaultStyle(); t.updateCell(t.row,t.col); t.cell(r,c).activeStyle(); t.updateCell(r,c); t.row=r; t.col=c; }, updateCell:function(r,c){ var input = this.Table.rows[r-1].cells[c-1].firstChild; var C = this.cell(r,c); input.style.borderWidth = C.borderWidth; input.style.borderColor = C.borderColor; if(''!=input.value && input.value!=C.value) C.value = input.value; input.value = C.value; input.focus(); }, show:function(){ var t=[],i=0,currenCell; t[i++] = '<table cellspacing=0 cellpadding=0 class="Table">'; var rCount = this.cells.length; var cCount = this.cells[0].length; var tt = this; var OnKeyDown = function(e){ e=e||event; switch(e.keyCode||e.charCode){ case 37: tt.moveTo(tt.row,tt.col-1); break; // move left case 38: tt.moveTo(tt.row-1,tt.col); break; // move up case 39: tt.moveTo(tt.row,tt.col+1); break; // move right case 40: tt.moveTo(tt.row+1,tt.col); break; // move down } } t[i++] = '<tr>'; var h = this.Header.rows[0]; for(var c=0; c<cCount; c++){ currenCell = this.cells[0][c]; t[i++] = '<td style="width:'+h.cells[c].offsetWidth+'px;"></td>'; } t[i++] = '</tr>'; for(var r=1; r<rCount; r++){ t[i++] = '<tr>'; for(var c=0; c<cCount; c++){ currenCell = this.cells[r][c]; t[i++] = '<td></td>'; } t[i++] = '</tr>'; } t[i++] = '</table>'; this._obj.lastChild.innerHTML = t.join(""); this.Table = this._obj.lastChild.firstChild; this.Table.style.width = this.Header.offsetWidth; window.onunload = function(){tt.cleanUp(tt)}; }, addHeaders:function(labelsList){ // labelList format: {name1:isSortable,name2:isSortable} var labels = [],h = [],k=0; for(var key in labelsList) labels.push({name:key,isSortable:labelsList[key]}); var rCount = this.cells[0].length; var cCount = this.cells.length; var t = this._obj; h[k++] = '<div><table cellspacing="0" cellpadding="0"><tr>'; for(var i=0;i<rCount;i++){ h[k++] = '<td>'; if(i<labels.length){ if(labels[i].isSortable){ h[k++] = '<select style="background:#99CCFF;"><option>'+labels[i].name+'</option>'; var options=[]; for(var j=0;j<cCount;j++){ var v = this.cells[j][i].value; if(false===options.search(v) && ''!=v){ options.push(v); h[k++] = '<option value="'+v+'">'+v+'</option>'; } } h[k++] = '</select>'; } else h[k++] = labels[i].name; } else h[k++] = ' '; h[k++] = '</td>'; } h[k++] = '</tr></table></div><br><div></div>'; t.innerHTML = h.join(""); this.Header = t.firstChild.firstChild; }, getValueList:function(collIndex){ var list = [],v; for(var i=0;i<this.cells.length;i++){ if(!list.toString().match(this.cells[i][collIndex].value)){ v = this.cells[i][collIndex].value; list.push('<option value="' + v +'">' + v + '</option>'); } } return list.join(''); }, cleanUp:function(tt){ // избегаем утечку памяти в Microsoft Internet Explorer for(var i=0;i<tt.cells.length;i++){ for(var j=0;j<tt.cells[0].length;j++){ tt.cells[i][j].parent=null; if(tt.cells[i][j].AutoCompleter){ tt.cells[i][j].AutoCompleter = null; } } } var inp = document.getElementsByTagName('INPUT'); for(var l=0;l<inp.length;l++){ inp[l].onclick = inp[l].onkeydown = null; } } }; } <html> <head> <style> .Table { border-collapse:collapse; } .Table td { border:1px solid #7F9DB9; height:18px; } </style> </head> <body> <script type="text/javascript" src="sheet.js"></script> <div id="SpreadSheet" align="center"></div> <script> var b = new Date(); var s = new sheet(document.getElementById('SpreadSheet')); s.cell(800,14); s.addHeaders({'Адрес установки':1,'Дом':1,'Под':1,'Switch':1,'IP адрес':1,'serial sw':1,'модуль':1,'1 модуль':1,'2 модуль':1,'Заказан':1,'Подготовлен':1,'Выдан':1,'Установлен':1,'Пометки':1}); s.show(); alert(((new Date()) - b)/1000); </script> </body> </html> Осталось только: 1) повесить обработку событий на саму таблицу (то есть обработчик будет всего один) 2) Завести один инпут (он будет редактировать значение текущей ячейки) |
Переписал генерацию таблицы и шапки на php, щас буду писать обработчики событий для перемещающегося INPUT. Что посоветуеш сделать ? removeChild INPUT из старой ячейки и appendChild INPUT в новую ? Или может сделать position:absolute и перемещать координаты INPUT? Мне вообщето больше второй вариант нравится.
<html> <head> <style> .SpreadSheet{border-collapse:collapse;} .SpreadSheet td {border:1px solid #7F9DB9;height:18px;} .SpreadSheet select{background:#99CCFF;} </style> </head> <body> <table class="SpreadSheet" id="3482624id"><th><select name="street"><option value="Адрес установки">Адрес установки</option><option value="Лесная">Лесная</option></select></th><th><select name="home"><option value="Дом">Дом</option><option value="25">25</option><option value="26">26</option></select></th><th><select name="porch"><option value="Под">Под</option><option value="1 подвал">1 подвал</option><option value="3 подвал">3 подвал</option></select></th><th><select name="dev_desc"><option value="Switch">Switch</option><option value="DES-3526">DES-3526</option></select></th><th><select name="IP"><option value="IP адрес">IP адрес</option><option value="10.100.40.28">10.100.40.28</option><option value="10.100.40.29">10.100.40.29</option></select></th><th><select name="serial_sw"><option value="serial sw">serial sw</option><option value="00-1C-F0-0F-9A-63">00-1C-F0-0F-9A-63</option><option value="00-1C-F0-0F-9A-9F">00-1C-F0-0F-9A-9F</option></select></th><th><select name="module0"><option value="модуль">модуль</option><option value="DEM-310GT V.D1">DEM-310GT V.D1</option></select></th><th><select name="module1"><option value="1 модуль">1 модуль</option><option value="E60N176001096">E60N176001096</option><option value="E60N176001091">E60N176001091</option></select></th><th><select name="module2"><option value="2 модуль">2 модуль</option><option value="E60N176001099">E60N176001099</option><option value="E60N176002084">E60N176002084</option></select></th><th><select name="orderDate"><option value="Заказан">Заказан</option><option value="39595">39595</option></select></th><th><select name="readyDate"><option value="Подготовлен">Подготовлен</option><option value="39597">39597</option></select></th><th><select name="givenDate"><option value="Выдан">Выдан</option><option value="39601">39601</option></select></th><th><select name="mountedDate"><option value="Установлен">Установлен</option><option value="39606">39606</option></select></th><tr><td>Лесная</td><td>25</td><td>1 подвал</td><td>DES-3526</td><td>10.100.40.28</td><td>00-1C-F0-0F-9A-63</td><td>DEM-310GT V.D1</td><td>E60N176001096</td><td>E60N176001099</td><td>39595</td><td>39597</td><td>39601</td><td>39606</td></tr><tr><td>Лесная</td><td>26</td><td>3 подвал</td><td>DES-3526</td><td>10.100.40.29</td><td>00-1C-F0-0F-9A-9F</td><td>DEM-310GT V.D1</td><td>E60N176001091</td><td>E60N176002084</td><td>39595</td><td>39597</td><td>39601</td><td>39606</td></tr></table> <script> function sheet(objTable){ var _sheet = { cell:document.createElement('INPUT'), moveTo:function(row,coll){}, init:function(){ // ОБРАБОТЧИКИ СОБЫТИЙ ДЛЯ INPUT } }; _sheet.init(); return _sheet; } s = new sheet(document.getElementById('3482624id')); </script></body> </html> |
Я думаю, что изменение таблицы будет вызывать нехилую перерисовку, так что надо минимизировать кол-во перерисовок таблицы. Соответственно, лучше в данном случае выглядит вариант с абсолютно спозиционированным инпутом, который находится ("летает") выше таблицы...
|
Я тут переписал свой код. Когда курсор на нижней строке и мы нажимаем вниз - добавляется новая строка. Но в опере текст который я туда записываю не отображается в таблице. В IE & FF, работает как надо. Как с этим бороться ?
<html> <head> <style> .SpreadSheet{border-collapse:collapse;} .SpreadSheet td {border:1px solid #7F9DB9;height:18px;} .SpreadSheet select{background:#99CCFF;} .SpreadSheetActivCell{border:3px #000000 solid;} </style> </head> <body> <table class="SpreadSheet" id="9394688id"><th><select name="street"><option value="Адрес установки">Адрес установки</option><option value="Землянского">Землянского</option><option value="Удмуртская">Удмуртская</option></select></th><th><select name="home"><option value="Дом">Дом</option><option value="9">9</option><option value="29">29</option></select></th><th><select name="porch"><option value="Под">Под</option><option value="2">2</option><option value="1">1</option></select></th><th><select name="dev_desc"><option value="Switch">Switch</option><option value="DES-3526">DES-3526</option></select></th><th><select name="IP"><option value="IP адрес">IP адрес</option><option value="10.102.32.13">10.102.32.13</option><option value="10.108.12.233">10.108.12.233</option></select></th><th><select name="serial_sw"><option value="serial sw">serial sw</option><option value="PL0A175001634">PL0A175001634</option><option value="PL0A175001635">PL0A175001635</option></select></th><th><select name="module0"><option value="модуль">модуль</option><option value="DEM-310GT V.D1">DEM-310GT V.D1</option></select></th><th><select name="module1"><option value="1 модуль">1 модуль</option><option value="E60N164003935">E60N164003935</option><option value="E60N166003929">E60N166003929</option></select></th><th><select name="module2"><option value="2 модуль">2 модуль</option><option value="E60N164004518">E60N164004518</option><option value="E60N164005657">E60N164005657</option></select></th><th><select name="orderDate"><option value="Заказан">Заказан</option><option value="39358">39358</option></select></th><th><select name="readyDate"><option value="Подготовлен">Подготовлен</option><option value="39358">39358</option></select></th><th><select name="givenDate"><option value="Выдан">Выдан</option><option value="39360">39360</option></select></th><th><select name="mountedDate"><option value="Установлен">Установлен</option><option value="39384">39384</option></select></th><tr><td>Землянского</td><td>9</td><td>2</td><td>DES-3526</td><td>10.102.32.13</td><td>PL0A175001634</td><td>DEM-310GT V.D1</td><td>E60N164003935</td><td>E60N164004518</td><td>39358</td><td>39358</td><td>39360</td><td>39384</td></tr><tr><td>Удмуртская</td><td>29</td><td>1</td><td>DES-3526</td><td>10.108.12.233</td><td>PL0A175001635</td><td>DEM-310GT V.D1</td><td>E60N166003929</td><td>E60N164005657</td><td>39358</td><td>39358</td><td>39360</td><td> </td></tr></table> <script> function sheet(objTable){ var _sheet = { rowIndex:null, collIndex:null, cell:document.createElement('INPUT'), _objTable:objTable, moveTo:function(row,coll){ try{ this.save(); var rowMax = this._objTable.rows.length-1; // число рядов var collMax = this._objTable.rows[1].cells.length; // число колонок //if(undefined==row || undefined==coll) return false; if(coll>collMax)coll=collMax; // проверяем чтобы не вылететь за граници таблицы if(row>rowMax)row=rowMax; // проверяем чтобы не вылететь за граници таблицы if(row<1)row=1 // проверяем чтобы не вылететь за граници таблицы if(coll<1)coll=1 // проверяем чтобы не вылететь за граници таблицы this.rowIndex = row; this.collIndex = coll; coll--; cell = this._objTable.rows[row].cells[coll]; var position = pos(cell); this.cell.style.top =position[0]; this.cell.style.left =position[1]; this.cell.style.width =cell.clientWidth; this.cell.style.height =cell.clientHeight; this.cell.value =cell.firstChild.nodeValue;/**/ }catch(e){ alert(e); return false; } return true; }, save:function(){ if(null==this.rowIndex || null==this.collIndex || undefined==this.rowIndex || undefined==this.collIndex ) return; var cell = this._objTable.rows[this.rowIndex].cells[this.collIndex-1]; if(this.cell.value!=cell.firstChild.nodeValue){ cell.firstChild.nodeValue = this.cell.value; } }, addRow:function(){ maxColl = this._objTable.rows[1].cells.length+1; var td,tr = document.createElement('TR'); tbody = this._objTable.rows[1].parentNode; tbody.appendChild(tr); for(i=0;i<maxColl;i++){ td = document.createElement('TD'); tr.appendChild(td); td.appendChild(document.createTextNode('')); } //this.moveTo(this.rowIndex+1,this.collIndex); //this.cell.focus(); tr=td=maxColl=null; }, init:function(){ // ОБРАБОТЧИКИ СОБЫТИЙ ДЛЯ INPUT this.cell.style.position='absolute'; document.body.appendChild(this.cell); this.cell.className='SpreadSheetActivCell'; this.cell.autocompliter='off'; var tt = this; this.cell.onkeydown = function(e){ lastCellIndex = tt._objTable.rows.length-1; e=e||event; switch(e.keyCode||e.charCode){ case 37: tt.moveTo(tt.rowIndex,tt.collIndex-1); break; // move left case 38: tt.moveTo(tt.rowIndex-1,tt.collIndex); break; // move up case 39: tt.moveTo(tt.rowIndex,tt.collIndex+1); break; // move right case 40: if(tt.rowIndex+1>lastCellIndex){tt.addRow();}tt.moveTo(tt.rowIndex+1,tt.collIndex); break; // move down } } objTable.onclick = function(e){ e=e||event; sorce = e.srcElement || e.target; var row = sorce.parentNode.rowIndex var coll= sorce.cellIndex+1; if(!tt.moveTo(row,coll))return; tt.cell.focus(); }; this.moveTo(1,1); this.cell.focus(); } }; _sheet.init(); return _sheet; } s = new sheet(document.getElementById('9394688id')); function pos(obj){ var x=0,y=0; do{ x += obj.offsetTop; y += obj.offsetLeft; }while(obj=obj.offsetParent) return [x,y]; } </script></body> </html> |
У меня в опере всё ОК
|
Наверное глупый вопрос, но всёже.... Как можно передать большой кусок html в функцию на JavaScript. В строку просто так не запихнёш - надо экранировать кавычки пробелы удалять. Я ничё лучше не придумал:
<div style="display:none" id="content123">сюда я помещаю весь текст<br><hr> и тд.</div> <script> function foo(content){ alert(content); } foo(document.getElementsById('content123').innerHTML); </script> |
и чем тебе это не нравится?
|
коряво как то)
|
сам ты корявый...
|
Цитата:
|
<html> <body> <div style="display:none" id="content123">сюда я помещаю весь текст<br><hr><img src="1.gif" /> и тд.</div> <script> function foo(content){ alert(content); } foo(document.getElementById('content123').innerHTML); </script> </body> </html> Никаких "<img src="1"> (как минимум в FF)" нет. |
ZoNT, не поверишь, но у меня закрывающие слэши убираются (FF2) :)
Т.к. браузер оперирует все-таки html-ом, а не xml-ом. В ИЕ, кстати, местами будут пропадать-появляться кавычки у аттрибутов. |
и тебя это чем-то волнует???
|
Меня это ни капельки не волнует, я не собираюсь передавать строки в js таким извратным способом. Я лишь говорю, что в js зачастую будет приходить не та строка, которая ушла из php.
|
ну если надо из пхп передавать именно строку, то надо сразу делать \/, \\ и т.д.
|
Надо предать много данных обратно на сервер. Загружаю таблицу с сервера (у меня в ней 14 полей). Пользователь в ней что то меняет или добавляет, а потом изменения нужно сохранить обратно на сервере. Как лучше передать измененные данные? Ведь если пользователь добавил 10 новых строк это уже 140 ячеек. Если отправлять эти данные постом через аякс можно ли как то проверить пришли ли они без ошибок? Или может какой то другой способ сдесь более применим ?
|
gagagogo,
Мне кажется лучше обходить на клиенте измененные ячейки и составлять JSON объект, который уже будет отправлен на сервер. Все-таки обмениваться html данными - не красиво. |
Нет, конечно я не буду пересылать ячейки наблици. Но делать JSON тоже не хочу потому что насервере нет расширени я для JSON, а парсить его в ручную чёт неохота. Думаю сфорганить строку с разделителями из выдранных из таблички данных. Не знаю как лучше сделать отправлять данные через аякс или форму?
|
Часовой пояс GMT +3, время: 12:18. |