Сортировка столбцов в таблице без перезагрузки.

Источник информации: Заметки HTML кодера

Иногда перед разработчиком стоит задача обеспечить сортировку столбцов в таблице с данными. Классическим решением является использование какого-нибудь серверного ЯП, который бы сортировал данные по определённому столбцу и отдавал полученную страницу клиенту.

Я хочу вам предложить альтернативное решение, работающее в W3C DOM-совместимых браузерах: Internet Explorer 5+ и Netscape Navigator 6+/Mozilla. Вообще, первым алгоритм сортировки предложил Пол Соуден (Paul Sowden), я же внёс в скрипт существенные коррективы.

Вот, что мы получаем в итоге (нажмите на заголовок, чтобы отсортировать колонку):

Имя Фамилия Сайт Переключалка стилей
Александр Шуркаев htmlcoder.visions.ru Угу
Пол Соуден idontsmoke.co.uk Угу
Джеффри Зельдман zeldman.com Угу
Аарон Будман youngpup.net Не-а
Глен Мерфи glenmurphy.com Не-а
Даниель Боган waferbaby.com Не-а
Ден Бенджамин hivelogic.com Угу

В других браузерах (например, Opera) таблица просто останется не отсортированная, в первозданном виде.

Теперь же о том, всё это дело реализуется. Буду объяснять по пунктам (изменения в плане HTML, CSS и JavaScript), чтобы легче было проследить логику.

HTML

Прежде всего, необходимо особым образом отформатировать таблицу, к которой вы собираетесь подключить возможность сортировки. Обратите внимание на код:

<table class="sort" align="center">
<thead>
<tr>
<td>Имя</td>
<td>Фамилия</td>
<td>Сайт</td>
<td>Переключалка стилей</td>
</tr>
</thead>
<tbody>
<tr>
<td>Александр</td>
<td>Шуркаев</td>
<td><a href="http://htmlcoder.visions.ru/">htmlcoder.visions.ru</a></td>
<td>Угу</td>
</tr>

<tr>
<td>Ден</td>
<td>Бенджамин</td>
<td><a href="http://hivelogic.com/">hivelogic.com</a></td>
<td>Угу</td>
</tr>
</tbody>
</table>

Как вы видите, необходимо указать теги thead (шапка таблицы) и tbody (основная часть). Обычно их мало кто использует, но здесь эти теги весьма кстати.

Вам также нужно создать две картинки, которые бы указывали текущий вариант сортировки — 0.gif (картинка сортировки вниз) и 1.gif (картинка сортировки вверх). Положите их, например, в корневой директории в папку «i». Я обычно называю папки с картинками для сайта именно так, но ничто не мешает использовать для наших целей классическую папку «images». Дело хозяйское, просто тогда вам нужно будет поменять в программке переменную img_dir (см. ниже пункт JavaScript).

В моём случае стрелочки выглядят так (можете их спионерить, я не против :-):

 

CSS

Задаём следующие классы в таблице стилей:

/* наша HTML таблица */
table.sort{
border-spacing:0.1em;
margin-bottom:1em;
margin-top:1em
}

/* ячейки таблицы */
table.sort td{
border:1px solid #CCCCCC;
padding:0.3em 1em
}

/* заголовки таблицы */
table.sort thead td{
cursor:pointer;
cursor:hand;
font-weight:bold;
text-align:center;
vertical-align:middle
}

/* заголовок отсортированного столбца */
table.sort thead td.curcol{
background-color:#999999;
color:#FFFFFF
}

Затем не забудьте указать у HTML таблицы класс sort (<table class="sort" align="center">).

JavaScript

Итак, мы подошли к «начинке» всего этого дела. Пропишите на странице следующий фрагмент:

<script type="text/javascript">
<!--
/*
originally written by paul sowden <paul@idontsmoke.co.uk> | http://idontsmoke.co.uk
modified and localized by alexander shurkayev <alshur@narod.ru> | http://htmlcoder.visions.ru
*/

var img_dir = "/i/"; // папка с картинками

// вспомогательная ф-ция, выдирающая из дочерних узлов весь текст
function getConcatenedTextContent(node) {
    var _result = "";
    if (node == null) {
        return _result;
    }
    var childrens = node.childNodes;
    var i = 0;
    while (i < childrens.length) {
        var child = childrens.item(i);
        switch (child.nodeType) {
            case 1: // ELEMENT_NODE
            case 5: // ENTITY_REFERENCE_NODE
                _result += getConcatenedTextContent(child);
                break;
            case 3: // TEXT_NODE
            case 2: // ATTRIBUTE_NODE
            case 4: // CDATA_SECTION_NODE
                _result += child.nodeValue;
                break;
            case 6: // ENTITY_NODE
            case 7: // PROCESSING_INSTRUCTION_NODE
            case 8: // COMMENT_NODE
            case 9: // DOCUMENT_NODE
            case 10: // DOCUMENT_TYPE_NODE
            case 11: // DOCUMENT_FRAGMENT_NODE
            case 12: // NOTATION_NODE
            // skip
            break;
        }
        i++;
    }
    return _result;
}

// флаг сортировки
var up = false;

// суть скрипта
function sort(e) {
    var el = window.event ? window.event.srcElement : e.currentTarget;

    if (el.tagName == "IMG") el = el.parentNode;

    var a = new Array();
    var name = el.lastChild.nodeValue;
    var dad = el.parentNode;

    var node, arrow, curcol;
    for (var i = 0; (node = dad.getElementsByTagName("td").item(i)); i++) {
        if (node.lastChild.nodeValue == name){
            curcol = i;
            if (node.className == "curcol"){
                arrow = node.firstChild;
                up = Number(!up);
                arrow.src = img_dir + up + ".gif";
            }else{
                node.className = "curcol";
                arrow = node.insertBefore(document.createElement("img"),node.firstChild);
                up = false;
                arrow.src = img_dir + Number(up) + ".gif";
            }
        }else{
            if (node.className == "curcol"){
                node.className = "";
                if (node.firstChild) node.removeChild(node.firstChild);
            }
        }
    }

    var tbody = dad.parentNode.parentNode.getElementsByTagName("tbody").item(0);
    for (var i = 0; (node = tbody.getElementsByTagName("tr").item(i)); i++) {
        a[i] = new Array();
        a[i][0] = getConcatenedTextContent(node.getElementsByTagName("td").item(curcol));
        a[i][1] = getConcatenedTextContent(node.getElementsByTagName("td").item(1));
        a[i][2] = getConcatenedTextContent(node.getElementsByTagName("td").item(0));
        a[i][3] = node;
    }

    a.sort();

    if (up) a.reverse();

    for (var i = 0; i < a.length; i++) {
        tbody.appendChild(a[i][3]);
    }
}

// ф-ция инициализации всего процесса
function init(e) {
    if (!document.getElementsByTagName) return;
    var thead = document.getElementsByTagName("thead").item(0);
    var node;
    for (var i = 0; (node = thead.getElementsByTagName("td").item(i)); i++) {
        if (node.addEventListener) node.addEventListener("click", sort, false);
        else if (node.attachEvent) node.attachEvent("onclick",sort);
        node.title = "Нажмите на заголовок, чтобы отсортировать колонку"; // задаём подсказку у заголовка таблицы
    }
    thead.getElementsByTagName("td").item(0).click(); // эмулируем клик на первом заголовке. в NN6/Mozilla не работает.
}

// запускаем ф-цию init() при возникновении события load
var root = window.addEventListener || window.attachEvent ? window : document.addEventListener ? document : null;
if (root){
    if (root.addEventListener) root.addEventListener("load", init, false);
    else if (root.attachEvent) root.attachEvent("onload", init);
}
//-->
</script>

Единственное, что вам нужно поменять в скрипте, так это переменную img_dir. Она должна указывать на каталог, где у вас лежат файлы 0.gif (картинка сортировки вниз) и 1.gif (картинка сортировки вверх).

Я решил не разбирать детально сам скрипт. Кому интересно, как всё работает, думаю, сам сможет понять.
 

Назад