Когда основным предназначением сайта является отображение обширных информационных таблиц, следует уделить особое внимание функциям сортировки информации. В этой статье я расскажу о четырех техниках: hover-эффект, режим «зебра», фильтрация и сортировка.
Создание таблиц
До начала работы с кодом я считаю необходимым объяснить основные принципы. Разметка для HTML-таблицы будет такой же, как и для любой другой таблицы, которую вы, возможно, уже пробовали делать, но требуются два дополнительных тега, о которых многие забывают. Шапку таблицы следует оформить тегами <thead></thead>. Основная часть оформляется тегами <tbody></tbody>. Сейчас я постараюсь объяснить вам разницу между заголовками таблицы и информации.
<table cellpadding="1" cellspacing="1" id="resultTable">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>City</th>
<th>State</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mannix</td>
<td>Bolton</td>
</tr>
...
</tbody>
</table>
Режим «зебра»
Режим «зебра» - распространенный метод представления информации, который прост в применении и при этом отлично выглядит. В режиме «зебра» четные и нечетные строки окрашены в разные цвета, что упрощает чтение информации по горизонтали. Это особенно удобно в таблицах, где много строк – благодаря разным цветам пользователь легко может найти информацию во всех столбцах. Для примера я использовал список людей со следующими характеристиками: имя, фамилия, город и штат. Обратите внимание – для максимального эффекта я чередую не только цвета фона, но и цвет текста.
А теперь займемся изучением режима «зебра». Прежде всего, следует создать новый файл CSS, прикрепленный к документу. Первый элемент, которым мы займемся – это table.
table {
background-color: white;
width: 100%;
}
Это все очень просто: задаем белый фон и ширину =100%. Далее займемся ячейками таблицы – <td>. Это может показаться странным – почему именно ячейками, а не всей строкой? Дело в том, что для корректного отображения в различных браузерах лучше задавать свойства фона у каждой ячеки отдельно.
tbody td {
background-color: white;
}
tbody td.odd {
background-color: #666;
color: white;
}
Здесь мы устанавливаем для нечетных строк таблицы другой цвет фона и шрифта. Кроме того, задаем стиль по умолчанию для всех элементов td, которые будут вписаны в четные строки. Вот и все, что требует CSS – я же говорил, что это очень просто! Теперь давайте посмотрим на код jQuery – здесь все ничуть не сложнее, нужно всего лишь выделить ячейку и добавить функцию addClassName.
$(document).ready(function() {
zebraRows('tbody tr:odd td', 'odd');
});
//используется для того, чтобы задать чередование стилей строк
function zebraRows(selector, className)
{
$(selector).removeClass(className).addClass(className);
}
Дополнительных пояснений к этому коду вроде бы не требуется – во-первых, обратите внимание, как мы перешли к применению функции: это идеальный вариант, так как, если мы меняем информацию в таблице асинхронно, без обновления страницы, мы хотим быть уверены, что строки сохранят прежний вид. Для этих же целей мы вводим функцию removeClass, так что если ряд, изначально бывший нечетным, станет четным, он автоматически сменит цвет. Сейчас это все может показаться вам непонятным, однако в дальнейшем, когда мы рассмотрим фильтрацию, все будет проще. Чтобы обеспечить возможность многократного использования кода, мы вводим селектор и имя класса в функцию, так что код может быть использован в проектах с различными именами классов и требованиями к селектору (например, на сайте, где много таблиц, одну из которых вы хотите раскрасить). Если вы посмотрите на функцию ready(), которая активируется при загрузке страницы, то увидите обращение к zebraRows(). Здесь мы указываем селектор и имя класса. Селектор использует специальную функцию jQuery syntax :odd, с помощью которой будут найдены все нечетные строки. Затем ищем все дочерние элементы строки, то есть ячейки. Код покажется очень простым всем, кто уже работал в jQuery, но с ним не должны возникнуть трудности и у новичков.
Примечание: В процессе использования jQuery для создания строк разного цвета можно отключить JavaScript. Я бы порекомендовал разместить нечетный класс на сервере с помощью кода PHP или статичного HTML, хотя это уже не относится к теме статьи.
Эффект курсора (hover-эффект)
Этот эффект отлично смотрится и может быть применен в тех случаях, когда требуется обратить внимание пользователя на строчку, на которую он наводит курсор – вдруг там есть что-то интересное. Все очень просто – используем jQuery, но сначала немного CSS.
...
td.hovered {
background-color: lightblue;
color: #666;
}
...
Вот и весь CSS-код, который нам потребуется – устанавливаем для ряда, который хотим выделить, бледно-голубой фон и серый цвет шрифта. Это можно так же легко сделать в jQuery.
...
$('tbody tr').hover(function(){
$(this).find('td').addClass('hovered');
}, function(){
$(this).find('td').removeClass('hovered');
});
...
Используем функцию hover() из библиотеки jQuery. Обратите внимание: функция активизируется, когда пользователь наводит курсор на строчку и автоматически прекращает действие, когда он убирает курсор. Когда курсор наведен на строчку, все ячейки строчки включаются в определенный класс и перекрашиваются. Когда курсор убирают, клетки исчезают из этого класса и приобретают прежний цвет. Вот это и есть эффект курсора – попробуйте!
Фильтрация информации
А теперь разберемся с фильтрацией информации. Если на сайте отображается большое количество информации, например, 1000 строк, как в моем примере, то обязательно следует предоставить пользователю возможность поиска нужной ему информации в таблице. Очень эффективная и относительно новая разработка, которой можно для этого воспользоваться – это Web2.0/AJAX, есть также некоторые программы от фирмы Apple, например iTunes. Наша цель – это сделать так, чтобы пользователь смог ввести поисковый запрос в поле ввода текста и получил результат в виде рядов таблицы, в которых содержится нужная ему информация. Это, конечно, сложнее, чем визуальные эффекты, но благодаря встроенным функционалам jQuery требуется не так уж и много кодирования.
Сначала напишем базовую функцию, которая займется выборками и текстом. Эта функция будет осуществлять поиск элементов, соответствующих запросу. Если такой элемент будет обнаружен, он автоматически заносится в класс видимых, в противном случае не показывается. Что мы делаем с видимыми элементами? После того, как элементы отсортированы, мы вновь запускаем функцию zebraRows, но задаем в jQuery игнорирование скрытых строк, и самый лучший способ для этого – задать класс visible.
Сам по себе поиск выполняется функцией JavaScript, которая называется search(). Однако, из-за некоторых особенностей работы стандарта консорциума WWW, если мы не воспользуемся еще и jQuery-функцией, то поиск будет осуществляться не только по информации в таблице, но и по различным тегам, из которых она состоит, так что это обязательно нужно сделать. Кроме того, это сделает возможным так называемый «ленивый поиск», при котором пользователь пишет не все слово или строку, а лишь часть. Функция search() работает с символами, поэтому следует убрать пробелы в конце и начале поискового запроса и вставить символы | в качестве разделителя слов.
//filter results based on query
function filter(selector, query) {
query = $.trim(query); //отрезаем пробелы
query = query.replace(/ /gi, '|'); //добавляем разделитель слов
$(selector).each(function() {
($(this).text().search(new RegExp(query, "i")) < 0) ? $(this).hide().removeClass('visible') : $(this).show().addClass('visible');
});
}
Все самое важное происходит в шестой строке, поэтому я ее прокомментирую. В пятой строке мы организуем поиск элементов, которые находятся в таблице и соответствуют запросу, а в шестой строке задаем работу кода. Эта строка может показаться новичкам сложной, однако, если разделить ее на составляющие, то окажется, что ничего сложного в ней нет. Если информация соответствует запросу, то она считается истинной и ставится слева от двоеточия, но до вопросительного знака. Если информация считается ложной, код ставится за двоеточием. Это стандартная схема «если-то», которая также может быть записана в таком виде:
...
if ($(this).text().search(new RegExp(query, "i")) < 0) {
$(this).hide().removeClass('visible')
} else {
$(this).show().addClass('visible');
}
...
Мы спрашиваем, соответствует ли результат работы функции search() требованию "< 0", потому что, если ничего не найдено, она покажет результат -1, а -1 всегда меньше 0, так что все правильно. Теоретически можно установить требуемое значение равным -1, но на практике удобнее и безопаснее сделать его меньше -1.
Итак, теперь мы заканчиваем писать функцию фильтрации, давайте воспользуемся jQuery, чтобы организовать представление информации, соответствующей поисковому запросу, с эффектом «зебра». Устанавливаем фильтрацию:
<label for="filter">Filter</label>
<input type="text" name="filter" value="" id="filter" />
А вот и код jQuery:
...
//По умолчанию каждый ряд видимый
$('tbody tr').addClass('visible');
$('#filter').keyup(function(event) {
//Если нажата клавиша esc или ничего не введено в поле поиска
if (event.keyCode == 27 || $(this).val() == '') {
//при нажатии клавиши esc поле поиска очищается
$(this).val('');
//нужно, чтобы каждый ряд был видимым раз ничего так и не введено
$('tbody tr').removeClass('visible').show().addClass('visible');
}
//если есть текст, включаем фильтр
else {
filter('tbody tr', $(this).val());
}
//снова активируем режим 'зебра'
$('.visible td').removeClass('odd');
zebraRows('.visible:odd td', 'odd');
...
Этот код довольно сложный, так что давайте разберем его шаг за шагом:
1. В начале мы используем функцию addClass('visible') для каждой строки, так как по умолчанию видно все.
2. Следующая строка – стандартная выборка, которая в данном случае представляет собой поисковый запрос и каждый раз, когда он найден в таблице, запускает следующую функцию. Обратите внимание, запрос состоит из различной информации, в том числе и сведений о том, какую клавишу нажимал пользователь.
3. В следующей строке используется как раз информации о нажатии клавиш: с помощью функции «если» мы проверяем, не нажал ли пользователь клавишу esc. Это очень полезное дополнение, с помощью которого пользователь сможет в любой момент отменить запрос и вернуться к полному объему информации. Многие поисковики игнорируют этот шаг, но мы не будем следовать их примеру.
4. Здесь же мы проверяем, не является ли окно запроса пустым – ведь некоторые просто стирают запрос, желая его отменить. В этом случае пользователь должен увидеть всю таблицу в качестве результата запроса, и нам следует удостовериться, что так и будет, иначе функция начнет искать пустые строки.
5. Если была нажата клавиша esc или же пользователь стер запрос, мы обнуляем запрос.
6. Далее мы показываем все ряды, как и собирались, и присваиваем им всем класс видимых. Перед этим мы удаляем из класса видимых все элементы, которые в нем находились, чтобы избежать дублирования.
7. Если же запрос требует выполнения, мы запускаем функцию фильтрации для поиска соответствующих ему строк.
8. После того, как мы отфильтровали ряды по видимости и невидимости, мы применяем к видимым рядам функцию «зебра». Убираем элементы, которые функция считает нечетными, предусматривая ситуацию, в которой нечетный ряд станет четным. Функция осталась такой же, какую я приводил в начале статьи, с той лишь разницей, что теперь мы работаем только с видимыми рядами.
Примечание: Неплохо будет использовать CSS для того, чтобы скрыть поле фильтрации, и разместить кнопку, открывающую его, так чтобы тем, у кого браузер не поддерживает JavaScript, тоже было удобно, когда они попытаются отсортировать информацию. Это делается так:
style.css
...
#filter { display: none; }
...
application.js
...
$('#filter').show();
...
Да уж, поработали мы на славу, так что сделайте перерыв, выпейте чаю или кофе, а затем мы займемся сортировкой.
Сортировка столбцов
Ну что, готовы? Тогда приступим!
Последним заданием на сегодня будет сортировка информации по одному из заголовков столбцов. Это стандартная практика известная пользователям как «кликни для сортировки». Когда пользователь нажимает на один из заголовков столбцов, информация в столбце сортируется в порядке возрастания, а если нажимает еще раз – в порядке убывания. Код будет достаточно сложным, так что слабонервных просим дальше не читать.
Замысел взят из книги Learning jQuery 1.3. Я немного модернизировал для большего удобства, но если вам все таки нужен больший контроль, то советую вам заглянуть в седьмую главу книги, в которой подробно описываются таблицы и применение jQuery.
До того, как мы приступим к написанию кода, следует определиться с тем, что мы будем делать для решения поставленной задачи. Мы воспользуемся функцией JavaScript sort(). В нашем случае требуется простая сортировка по алфавиту и числам, так что придется просто сравнивать значения и решать, какое поставить выше, а какое ниже. Так как сортировка может проводиться как по возрастанию, так и по убыванию, мы воспользуемся классами CSS для того, чтобы определить, как сортируется информация в настоящий момент, и менять способ сортировки по ходу дела. Затем мы переставляем строки в требуемом порядке. Вроде бы много всего, но благодаря быстрой работе JavaScript пользователю не придется долго ждать результатов сортировки. Все эти действия будут привязаны к щелчку мышью по заголовку столбца.
Как всегда, начнем с кода CSS: он перед вами.
th.sortable {
color: #666;
cursor: pointer;
text-decoration: underline;
}
th.sortable:hover { color: black; }
th.sorted-asc, th.sorted-desc { color: black; }
Все заголовки, которые могут быть использованы для сортировки, попадают в класс «сортируемые», а благодаря эффекту курсора при наведении курсора на заголовки они примут вид ссылок. Кроме того, мы воспользуемся доступными для CSS-классов формами сортировки по возрастанию и убыванию. Неплохо было бы и добавить стрелки, направленные вверх или вниз в зависимости от текущей формы сортировки, хотя я и не стал этого делать. Теперь переходим к коду JavaScript и всем сложностям сортировки, которые, тем не менее, сократились с помощью jQuery. Нижеприведенный код относится к функции ready(), которую мы начали выше.
//захватываем все ряды заголовка
$('thead th').each(function(column) {
$(this).addClass('sortable').click(function(){
var findSortKey = function($cell) {
return $cell.find('.sort-key').text().toUpperCase() + ' ' + $cell.text().toUpperCase();
};
var sortDirection = $(this).is('.sorted-asc') ? -1 : 1;
//step back up the tree and get the rows with data
//for sorting
var $rows = $(this).parent().parent().parent().find('tbody tr').get();
//’’цепляем’’ (loop through) все ряды и ищем
$.each($rows, function(index, row) {
row.sortKey = findSortKey($(row).children('td').eq(column));
});
//сравниваем и сортируем ряды в алфавитном порядке
$rows.sort(function(a, b) {
if (a.sortKey < b.sortKey) return -sortDirection;
if (a.sortKey > b.sortKey) return sortDirection;
return 0;
});
//добавляем ряды в правильном порядке к низу таблицы
$.each($rows, function(index, row) {
$('tbody').append(row);
row.sortKey = null;
});
//Определяем порядок сортировки
$('th').removeClass('sorted-asc sorted-desc');
var $sortHead = $('th').filter(':nth-child(' + (column + 1) + ')');
sortDirection == 1 ? $sortHead.addClass('sorted-asc') : $sortHead.addClass('sorted-desc');
//определяем колонку, которую надо отсортировать
$('td').removeClass('sorted')
.filter(':nth-child(' + (column + 1) + ')')
.addClass('sorted');
$('.visible td').removeClass('odd');
zebraRows('.visible:even td', 'odd');
});
});
Длинный код, да? Давайте разделим его на кусочки. В первой части кода рассматриваются заголовки, а затем они записываются в класс сортируемых.
...
$('thead th').each(function(column) {
$(this).addClass('sortable').click(function(){
...
Обратите внимание, что можно разрешить сортировку только некоторых столбцов, убрав обращение к функции addClass() и сменив выборку с 'thead th' на что-то вроде 'thead th.sortable'
Далее в коде мы привязываем функцию к изменяющемуся событию. Это звучит немного странно, но те, кто уже занимался программированием, должны знать, что это обычное дело. Это позволит функции работать с нужным пользователю заголовком. Функция findSortKey обеспечит выбор столбца сортировки и предпочтение его всем остальным столбцам – например, если кликнули по третьему столбцу, мы должны расположить строчки в соответствии с отсортированными данными из этого столбца. После включения этой функции мы определяем порядок сортировки – по возрастанию или убыванию. Это делается посредством задания класса 'sorted-asc' для заголовков, если информация сортируется по возрастанию, а нам нужно сменить порядок; в противном случае по умолчанию устанавливается сортировка по возрастанию – это нужно, чтобы в случае необходимости сменить убывающую сортировку на возрастающую. Результатом работы функции будут числа 1 или -1, позже я объясню, почему.
...
var findSortKey = function($cell) {
return $cell.find('.sort-key').text().toUpperCase() + ' ' + $cell.text().toUpperCase();
};
var sortDirection = $(this).is('.sorted-asc') ? -1 : 1;
...
Теперь нам нужно найти все строки, пересекающиеся с этим столбцом, и расположить их в нужном порядке. Для этого есть специальная функция jQuery get(). Так как текущий параметр выборки – это заголовки столбцов, нам придется сделать три шага назад по схеме и найти table>tbody>tr>td. Вроде бы кажется сложным, но на самом деле это не так. Просмотрев все столбцы, мы выясняем, по какому из них будет проводиться сортировка. Это делается путем сравнения номера столбца (нумерация начинается с 0) с номером столбца, на который нажал пользователь. Затем нужный столбец передается в функцию findSortKey, чтобы мы могли задать атрибут sortKey, состоящий из заголовка столбца и текста в нем. Такой порядок работы является оптимальным для больших текстовых массивов.
...
var $rows = $(this).parent().parent().parent().find('tbody tr').get();
$.each($rows, function(index, row) {
row.sortKey = findSortKey($(row).children('td').eq(column));
});
...
Затем идет функция sort(), о которой я уже говорил. Она работает со строками, которые мы задали функцией get(). Единственный параметр функции – это тип сортировки. Функция сравнивает значения информации в строках и определяет, в каком порядке их расположить. Как раз в этом месте используются значения функции sortDirection – 1 и -1.
...
// сравниваем и сортируем ряды в алфавитном порядке
$rows.sort(function(a, b) {
if (a.sortKey < b.sortKey) return -sortDirection;
if (a.sortKey > b.sortKey) return sortDirection;
return 0;
});
...
Далее код добавляет строку за строкой в структуру DOM. Очень удобно то, что функция не копирует строки, а заменяет их, что помогает ей работать быстрее. После того, как все сделано, строки расставляются в правильном порядке.
...
$.each($rows, function(index, row) {
$('tbody').append(row);
row.sortKey = null;
});
...
Все сделано – осталось только кое-что подчистить. Берем клетки таблицы, очищаем их от принадлежности к различным классам, а затем фильтруем по указанному столбцу. Если вдруг мы решим перекрасить столбец сортировки с другой цвет, то опять же воспользуемся CSS.
...
.sorted { background-color: green; }
...
Последнее, что нам нужно сделать – это удалить предыдущие сведения о четных и нечетных рядах и заново применить фильтр «зебра».
...
$('.visible td').removeClass('odd');
zebraRows('.visible:even td', 'odd');
...
Вот так делается простейшая сортировка. Помните, что она работает только с числами и буквами и не воспринимает, к примеру, валюту или даты – для этих целей потребуется более сложный код, который не входит в нашу сегодняшнюю программу.
Итоги
В этой статье я рассказал вам, как приукрасить таблицу с помощью jQuery. Такие дополнения очень удобны как для вас, так и для пользователей. У пользователя теперь есть возможность сортировать и фильтровать информацию, а у вас есть легкий и удобный код.