Простой сортировщик HTML таблиц
Simple Table Sorter v 0.01
Подключение: 1) в head HTML-документа добавить две строчки: <link rel='stylesheet' href='tabsort0.css' type='text/css'> <script type='text/javascript' src='tabsort0.js'> 2) Добавить сортируемым таблицам атрибут class='sortable'. 3) Распаковать архив SimpleTableSorter.zip в папку с HTML документами. Функциональность: 1) щелчок по заголовку таблицы сортирует строки; 2) Ctrl + Click по заголовку таблицы приводит таблицу в первоначальное состояние (reset). Рабочий пример: http://ir2.ru/sorters/table400.htm Два года писал этот код, и всё никак не могу закончить, всё время кажется, что чего-то в нём не хватает. Он небольшой, можно привести целиком: -function(){ var hc = function (s, c) {return (" " + s + " ").indexOf(" " + c + " ") !== -1}, ac = function (e, c) {var s = e.className; if (!hc(s, c)) e.className += " " + c}; prepTabs = function (t){ var el, th, ts = (t && t.className) ? [t] : document.getElementsByTagName("table") for (var e in ts) { el = ts[e] if (!hc(el.className, "sortable")) continue if (!el.tHead) { th = document.createElement("thead") th.appendChild(el.rows[0]) el.appendChild(th) } th = el.tHead ac(th, "c_0_c") th.title = "Сортировать" th.onclick = clicktab el.sorted = NaN //reset el.tb = el.tBodies[0] el.tb_res = el.tb.cloneNode(true) el.th_res = th.cloneNode(true) el.a_color = 0 } } var clicktab = function (e) { e = e || window.event var obj = e.target || e.srcElement; while (!obj.tagName.match(/^(th|td)$/i)) obj = obj.parentNode var i = obj.cellIndex, t = obj.parentNode, cn = obj.className, verse = /d\_\d+\_d/.test(cn); while (!t.tagName.match(/^table$/i)) t = t.parentNode var j = 0, rows = t.tb.rows, l = rows.length, c, v, vi; if (e.ctrlKey) { /* reset */ t.replaceChild(t.tb_res, t.tb); t.replaceChild(t.th_res, t.tHead); prepTabs(t); return; } if (i !== t.sorted) { if (t.a_color < 9) t.a_color++ else t.a_color = 1 t.sarr = [] for (j; j < l; j++) { c = rows[j].cells[i] v = (c) ? (c.innerHTML.replace(/\<[^<>]+?\>/g, '')) : '' vi = Math.round(100 * parseFloat(v)).toString() if (isFinite(vi)) while (vi.length < 10) vi = '0' + vi else vi = v t.sarr[j] = [vi + (j/1000000000).toFixed(10), rows[j]] //c.innerHTML = t.sarr[j][0] } } t.sarr = (verse) ? t.sarr.reverse() : t.sarr.sort() t.sorted = i var dir = (verse) ? "u" : "d", new_cls = dir + "_" + t.a_color + "_" + dir, a_re = /[cdu]\_\d+\_[cdu]/; if (a_re.test(cn)) obj.className = cn.replace(a_re, new_cls) else obj.className = new_cls for (j = 0; j < l; j++) t.tb.appendChild(t.sarr[j][1]) obj.title = "Отсортировано по " + ((verse) ? "убыванию" : "возрастанию") } window.onload = prepTabs }() |
несколько советов
а так.. код ужат уже. переменные с именами в одну букву.. зачем это делать самому, если GCC сделает это сам? var hc = function (s, c) {return (" " + s + " ").indexOf(" " + c + " ") !== -1}, var hc = function (s, c) {return !!~(" " + s + " ").indexOf(" " + c + " ") }, .. window.onload = prepTabs document.addEventListener("DOMContentLoaded", prepTabs, false ); |
Вопрос. Как справляется сортировщик с большими таблицами (например, несколько тысяч строк)?
|
Цитата:
http://ir2.ru/sort1/table2000_1.htm |
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
хотя можно и без них. все равно дальше будет преобразовываться в буль :) |
если цель сократить код, то я бы "избавился" от всех... или почти всех var
например вот этот кусочек ... prepTabs = function (t){ var el, th, ts = (t && t.className) ? [t] : document.getElementsByTagName("table") for (var e in ts) { ... можно заменить на ... prepTabs = function (t, el,th,ts,e){ ts = (t && t.className) ? [t] : document.getElementsByTagName("table") for (e in ts) { ... |
Цитата:
...ну, и сокращение тут происходит не всегда: вариант "function(a, b, c){a = 1; b = 2; c = 3;}" на три буквы длиннее традиционного "function(){var a = 1, b = 2, c = 3;}" |
Цитата:
|
Исправления предлагаю. Замените строку
Код:
for (var e in ts) { Код:
for(var e = 0; e < ts.length; e++) { |
Цитата:
|
Для
Array часто добавляют реализацию стандартных методов в прототип для старых браузеров, поэтому el может оказаться, например, "forEach" или "indexOf" … можно конечно добавить проверку hasOwnProperty , но лучше перебирать по индексам элементов. |
Цитата:
Цитата:
|
Согласен, for in выглядит несколько некошерным, таким "неформалом". Но, к сожалению, я это знал и раньше, и прошёл много всяких граблей на эту тему, использовать теперь не боюсь. Оставлю пока как "каприз художника".
О, я много где сэкономил на производительности! :-) Но вы всё равно не найдёте. Да я и сам сейчас не вспомню всего. Но можно ведь производительность просто измерить. В первой версии я сэкономил на коде (измерителя нет). Но вот в следующей (Simple Table Sorter v0.03) можно посмотреть скорость: http://ir2.ru/sort0.03/table1000.htm Можно даже сравнить по скорости с некоторыми другими сортировщиками (желательно в IE): http://ir2.ru/sorters/fd/ http://ir2.ru/sorters/la/ http://ir2.ru/sorters/standardista/ Это, конечно, очень приблизительно (измеритель прикручивал к чужому коду, мог не всё учесть и неправильно назвать какие-то моменты). Ну, плюс я добрый - добавил в standardista небольшой хак, без которого в IE сортировка работала бы десятки секунд. |
Кстати заметил, что последнее время, с появлением Object.keys, у меня в коде вообще исчезли for-in, теперь пишу:
var keys = Object.keys(obj), i = keys.length; while (i--) { obj[keys[i]]… } в браузерах поддерживающих Object.keys разница в скорости с вариантом: for (key in obj) { if (obj.hasOwnProperty(key)) { obj[key]… } } несущественна. |
Цитата:
Object.keys(obj).forEach(function(key) { // ... }); |
Как-то расточительно на каждую итерацию выполнять функцию, когда можно этого не делать
|
Да перестань, на фоне любой операции внутри функции вызов самой функции будет незначительным. Выигрыш у тебя будет только если ты проверяешь на скорость различные виды ничего не делающих циклов.
А вот создающийся скоп внутри функции реально полезен. |
Еще у меня из-за замыкания начинается паранойя:
proto = { method: function (…) { var a, b, c, d, …; Object.keys(…).forEach(function (…) { //к примеру, тут не нужны a, b, c, d }); } } приходится выносить в отдельный метод: proto = { _method: function (…) { //тут this → window }, method: function (…) { var a, b, c, d, …; Object.keys(…).forEach(this._method); } } но метод в прототипе, ничего не делающий с this, кажется лишним, выносим его в отдельный объект: utils = { method: function (…) {…} } proto = { method: function (…) { var a, b, c, d, …; Object.keys(…).forEach(utils.method); } } в итоге придется искать в коде, что же там за utils.method, который возможно состоит из пары строчек и самостоятельно не имеет смысла, появляется проблема с передачей дополнительных переменных. а можно было всего-лишь написать: proto = { method: function (…) { var a, b, c, d, …, keys = Object.keys(…), i = keys.length; while (i--) { … } } } поэтому forEach использую, только когда действительно нужен локальный скоп, а еще в светлом будущем ожидается let |
proto = { method: function (…) { var a, b, c, d, …, keys = Object.keys(…), i = keys.length; while (i--) { //к примеру, тут не нужны a, b, c, d } } } И в чём разница? |
Ну так они никуда не замыкаются, паранойя не наступает :D
|
А что меняется от того, замыкаются они или не замыкаются? Не пойму, откуда паранойя растёт.
|
Да ничего страшного не происходит. Я понимаю, что разница будет заметна только в тестах, где 100500 раз одно и тоже повторяют, но просто зачем все эти лишние действия (создание функции, связь скопов, call, …) будут происходить, если используя while, их не будет.
|
я тоже сначала заморачивался по этому поводу, а потом перестал, когда сравнил скорость...
|
Цитата:
Цитата:
вот, float, это правильный подход при борьбе с паранойей, я считаю :) |
Цитата:
|
Цитата:
Но на следующем - возникает потребность не в совершенстве кода, а в новой функциональности. И маховик начинает раскручиваться заново: добавляем, например, раскраску строк в зависимости от значений, и оказывается, что простой алгоритм не способен решить эту задачу. |
Цитата:
|
Цитата:
И, кстати, маховик провернулся уже третий раз. О версии 0.03 с раскраской ячеек в зависимости от содержания я уже говорил (http://ir2.ru/sort0.03/table400.htm), код с комментариями 9К. А вот версия 0.04, с визуальными настройками для пользователя (можно мышкой выбирать типы данных для сортировки или указывать очередь предопределённой сортировки для разных столбцов: http://ir2.ru/sort0.03/table404.htm (код 18К, а ничего, кроме удобства для пользователей, не добавилось!). Никаких готовых визуальных компонентов, всё на коленке рисовал! А вот пару функций для куки позаимствовал у соседей (хватило ума понять, что свои хуже :-)). Причём, как-то вот выбрал так, что getCookie мне больше понравились у Riim (нафига возвращать null, если в этом случае это совпадает по работе с undefined), а вот setCookie взял у Kolyaj (ибо не нужен мне сложный массив параметров, хотя теоретически это точнее). |
Часовой пояс GMT +3, время: 03:55. |