RizVN Login



Автоматическая нумерация строк в таблице во всплывающем окне средствами jQuery

Введение: Автоматическая нумерация строк

Достаточно часто, при использовании таблиц на веб-страницах, возникает необходимость в автоматической нумерации строк. И причин тому может быть много. Использование номера вместо сложных аббревиатур или названий. Подсчет количества позиций как в общем случае, так и для диапазона строк. И другие. Однако, использование нумерации в таблицах связано с рядом нюансов, которые учитываются далеко не во всех решениях. Вот, некоторые из них:

  • Ширина таблицы. Каждая добавленная ячейка автоматически увеличивает ширину таблицы, что чревато вылезанием за края видимой области на небольших мониторах. Этот нюанс особенно хорошо чувствуется, когда столбцов в таблице от 10. 
  • Стартовый номер строки. Таблица может динамически обновляться. Например, достаточно часто при отображение больших массивов данных, используется постраничное отображение, где данные загружаются по мере необходимости. И если решение не учитывает стартовый сдвиг для нумерации строк, то может возникать проблема, когда пользователю будет не совсем понятно, какой же реальный номер у строки. Безусловно, умножить номер страницы на количество строк и добавить к текущему номеру - не сложная задача, но, порой, она может лишь отнимать время. Особенно, если речь о частом использовании номеров строк.
  • Лишние данные. Если номер строки генерируется на серверной стороне, то кроме реальных данных, каждый раз будут передаваться лишние данные. Безусловно, достаточно часто, номера не будут занимать много трафика. Однако, когда речь будет идти о частом использовании или о большой аудитории, то это будет лишь дополнительной нагрузкой на серверную часть, которая легко решается на клиентской части.
  • Сортировка строк. Если строки в таблице можно сортировать по столбцам, то обновление счетчика строк должно быть предусмотрено решением. К примеру, если вы используете для нумерации одно решение, а для сортировки другое, то необходимо, чтобы была возможность после сортировки выставить корректные номера строкам. В противном случае, такая нумерация будет бессмысленной.
  • Простота решения. Нумерация строк - это не такая сложная задача, чтобы нужно было решать ее тяжеловесными плагинами и фреймворками. В данном случае речь идет о том, что, иногда, требуется нумерация строк и только. Например, если речь идет о статических таблицах. Поэтому должна существовать возможность отдельно добавить нумерацию, без необходимости преобразования таблицы или применения всех возможностей плагинов и фреймворков.
  • И другие...

Безусловно, на этом список нюансов не заканчивается, но даже этих нюансов вполне достаточно, чтобы понять, что даже у такой простой задачи, как нумерация строк, есть особенности, не учет которых может сделать решение непригодным. 

 

Существующие решения для автоматической нумерации строк

Существует немало готовых решений для автоматической нумерации строк в таблице, но, в основном, все они сводятся к следующим:

  • Нумерация на серверной стороне. Самый простой способ, который часто используется в решениях, где практически все взаимодействие организовано через серверную сторону. Безусловно, такой подход будет простым и учитывающим как стартовый номер строки, так и сортировку. Однако, проблемы широких таблиц и передачи лишних данных никак не решаются.
  • Нумерация средствами js/jQuery в отдельном поле таблицы. Этот способ базируется на том, что в таблице создается столбец, ячейки которого автоматически наполняются на стороне клиента, т.е. в браузере. Такие решения могут быть простыми и учитывающими стартовые номера, сортировку строк, а так же решающими проблему передачи лишних данных (так как часто, скрипты кэшируются браузером). Однако, проблема широких таблиц никак не решается. 
  • Нумерация средствами CSS. Это достаточно интересный подход, где все номера строк проставляются на основе выражений в CSS. Однако, применение их связано не только с проблемой широких строк, но и с их поддержкой в разных версиях браузеров. Кроме того, использование CSS для решения такого рода задач в сложных проектах может приводить к ошибкам. Так как смешиваются функциональные и визуальные задачи.
  • Замена таблицы на нумерованный список (ol). Изменение структуры таблиц - в некоторых случаях может быть вполне оправданным решением. Особенно, когда речь идет о выводе списка из одного столбца данных, ведь так учитываются практически все нюансы (кроме ширины строк, но в случае с простым списком из одного столба проблемы нет). Однако, изменение структуры - означает изменение структуры, со всеми вытекающими отсюда проблемами. Так, например, к такой таблице вы уже не сможете применить другие скрипты, так как они рассчитывают получить на входе html тэг table, а не ol. Или же вам придется использовать другие селекторы. И прочие особенности.
  • Фреймворки или плагины для таблиц. Существует масса готовых решений для таблиц, включая плагины и фреймворки. Однако, обычно, задача автоматической нумерации является второстепенной. Это означает, что для простой нумерации строк вам необходимо будет применять все возможности таких решений со всеми вытекающими отсюда проблемами. Что в свою очередь будет означать, не только тяжеловесность решения, но и необходимость корректировать все действия с таблицей. Вы используете собственное решение, для постраничной загрузки данных? Или может вы удаляете и добавляете строки из собственных скриптов? Тогда готовьтесь к тому, что вам придется изучить, как это делается средствами этих же плагинов и фреймворков. Кроме того, проблема ширины таблицы никак не решается, так как, обычно, номер указывается в отдельном столбце.

Как видно, существующие средства не учитывают все приведенные выше нюансы, а некоторые чреваты либо дополнительными проблемами, либо необходимостью выполнения дополнительных действий.

Самым наиболее подходящим способом было бы использование скриптов для автоматической нумерации, если бы не проблема с шириной таблицы. 

После некоторого рассуждения, была придумана идея использовать всплывающие окна вместо столбца с номерами строк. В таком случае, легко решается проблема ширины таблицы, ведь не нужно добавлять столбец. Кроме того, практически на любой странице, всегда есть место по краям таблиц. Так что такое окно будет всегда видно. Соответственно, команда "Ida-Freewares.ru" реализовала такое решение.

Примечание: Если вам не интересны подробности реализации, то вы можете сразу перейти к главе "Смотрим результат и пример использования" и скачать готовый проект в самом конце статьи.

 

Реализуем нумерацию строк во всплывающем окне на jQuery

Прежде, чем реализовывать скрипт, необходимо определиться с его возможностями и ограничениями:

  • Решение должно использовать js/jQuery и быть простым. Итоговое решение должно быть простым и понятным. Это касается как использования только стандартных возможностей js/jQuery, так простоты организации кода. Всегда должна оставаться возможность легко подправить решение под свои нужды.
  • Должны решаться все указанные вначале статьи нюансы.
    • Ширина таблицы не должна меняться
    • Должна быть возможность указать стартовый номер строк
    • Лишние данные не должны передаваться
    • Всегда должна быть возможность легко перенумеровать строки
    • Решение должно быть простым и удобным с точки зрения использования.
  • Возможность указывать позицию всплывающего окна. В зависимости от страниц и визуального отображения таблиц, такое всплывающее окно может находиться в разных местах, и механизм должен это предусматривать.

Как видите, набор возможностей и ограничений получился вполне простой и логичный. Так что можно приступать к реализации.

 

Составим тестовый проект

Теперь, составим тестовый проект со следующей структурой:

  • css - каталог со стилями
    • template.css - файл стилей
  • js - каталог для скриптов
    • jquery-numtiptable.js - скрипт для автоматической нумерации строк в таблице
  • index.html - тестовая форма

Примечание: Как это уже не раз отмечалось на сайте Ida-Freewares.ru, всегда старайтесь создавать тестовые проекты максимально приближенными к структуре настоящих проектов. Это поможет вам отловить ошибки и проблемы, связанные со структурой, еще на этапе разработки.

 

Файл стилей - template.css

Большую часть файла со стилями занимают стили таблицы в тестовом примере. Наибольший интерес представляют именно стили самого окна:

/* ... */
.table-tipnum
{
    position:absolute;
    background-color:#dedede;
    padding: 3px;
    border:1px solid #fff;
/* По умолчанию элемент всплывающего окна отображается поверх всех остальных */
    z-index: 1000;
/* По умолчанию скрываем элемент */
    left: -9999px;
}
 
.table-tipnum p
{
    margin:0;
    padding:0;
font-size: 13px;
    color:#fff;
    background-color: #2C329D;
    padding:2px 5px;
}
/* ... */

Примечание: Остальная часть стилей находится в архиве с проектом в конце статьи. 

Совет: Старайтесь всегда добавлять в тестовые проекты хотя бы минимальный дизайн. Так вы сможете отловить проблемы и ошибки с дизайном еще на этапе разработке. К примеру, если таблица будет уходить за края экрана, то отображать нумерацию в невидимой для пользователя области будет не совсем корректно, так как даже для того, чтобы узнать, что такое всплывающее окно существует, ему необходимо прокрутить экран. Кроме того, если, к примеру, правая граница будет граничить с областью страницы, то всплывающее окно, расположенное справа от строки, будет отображаться в невидимой для пользователя области.

 

Файл скрипта для автоматической нумерации строк в таблице - jquery-numtiptable.js

Файл скрипта для автоматической нумерации строк достаточно простой и имеет все необходимые пояснения для его использования, поэтому приводится целиком:

 
(function (parentObject) {
    // Проверяем на повторную инициализацию
    if (parentObject.numTipTable)
        return;
 
    ////////////////////////////////////////////////
    // Создаем общий интерфейс для создания элементов
    ////////////////////////////////////////////////
    parentObject.numTipTable = {
        ////////////////////////////////////
        // function _getTooltip
        ////////////////////////////////////
        // Получаем элемент для отображения
        // Функция для внутреннего использования
        ////////////////////////////////////
        _getTooltip: function (table) {
            // Если элемент со всплывающем окном для таблицы был уже создан, 
            // то возвращаем его
            if ($(table).data('tipnumid'))
                return $('.table-tipnum.tipnum-' + $(table).data('tipnumid'));
 
            // Создаем всплывающее окно для таблицы
            var tipId = Math.floor(Math.random() * 1000000),
                numTip = $('<div class="table-tipnum tipnum-' + tipId + '"><p></p></div>');
            // Добавляем в тело страницы
            $('body').append(numTip);
            // Сохраняем идентификатор, чтобы при повторной инициализации
            // использовать уже имеющийся элемент
            $(table).data('tipnumid', tipId);
            return numTip;
        },
 
        ////////////////////////////////////
        // function num
        ////////////////////////////////////
        // table - селектор или элемент таблицы
        // options: { - передаваемые параметры
        //  pos - позиция всплывающего окна относительно строки в таблице 
        //        (left, top, right, bottom)
        //  align - при отображении окна сверху или снизу, указывает его месторасположение по горизонтали
        //         (left, center, right)
        //  valign - при отображении окна справа или слева, указывает его месторасположение по вертикали
        //         (top, center, bottom)
        //  filter - селектор для выбора нужных строк 
        //        (применяется в случае, если используется скрытые строки в таблице, чтобы исключить их из выборки)
        //  start - номер первого элемента 
        //        (по умолчанию 1)
        // }
        ////////////////////////////////////
        num: function (table, options) {
            // Накладываем пользовательские настройки 
            // на настройки по умолчанию
            var _options = $.extend({
                pos: 'left',
                align: 'center', // left, center, right
                valign: 'center', // top, center, bottom
                filter: '*',
                start: 1
            }, options || {}),
                // сохраняем ссылку на элемент управления
                self = this,
                // получаем всплывающее окно
                numTooltip = self._getTooltip(table),
                // собираем строки в таблице
                // (использование tbody обязательно
                //  так как селектор '> tbody > tr' используется для того, 
                //  чтобы не смешивать строки таблицы со внутренними таблицами и заголовками, е
                searchElements = $(table).find('> tbody > tr').filter(_options.filter);
            
            // При наведении мышки, отображаем всплывающее окно
            searchElements.mouseover(function () {
                // Получаем индекс строки в выборке
                var cntItem = searchElements.index(this),
                    // Получаем положение элемента относительно окна страницы
                    elOffset = $(this).offset(),
                    // Сохраняем полностью занимаемое пространство элементом
                    elSize = {
                        width: $(this).outerWidth(),
                        height: $(this).outerHeight()
                    };
 
                // Записываем номер элемента
                numTooltip.find('p').text('' + (_options.start + cntItem));
 
                // Сохраняем размеры всплывающего окна
                var tipSize = {
                        width: numTooltip.outerWidth(),
                        height: numTooltip.outerHeight()
                    },
                    // Определяем набор для сдвига по вертикали
                    valign = {
                        'top': 0,
                        'center': Math.floor((elSize.height - tipSize.height) / 2),
                        'bottom': elSize.height - tipSize.height
                    },
                    // Определяем набор для сдвига по горизонтали
                    align = {
                        'left': 0,
                        'center': Math.floor((elSize.width - tipSize.width) / 2),
                        'right': elSize.width - tipSize.width
                    };
 
                // Отображаем всплывающее окно
                numTooltip.css({ opacity: 0.8, display: 'block' });
                
                // Далее указываем место на экране
                if (_options.pos === 'left') {
                    numTooltip.css({
                        top: elOffset.top + (valign[_options.valign] || 1),
                        left: elOffset.left - 5 - tipSize.width
                    });
                }
                else if (_options.pos === 'right') {
                    numTooltip.css({
                        top: elOffset.top + (valign[_options.valign] || 1),
                        left: elOffset.left + elSize.width + 5
                    });
                }
                else if (_options.pos === 'top') {
                    numTooltip.css({
                        top: elOffset.top - 5 - tipSize.height,
                        left: elOffset.left + (align[_options.align] || 1)
                    });
                }
                // Если указана некорректная позиция, то считаем эквивалентным выбору "bottom"
                else /* bottom */{
                    numTooltip.css({
                        top: elOffset.top + elSize.height + 5,
                        left: elOffset.left + (align[_options.align] || 1)
                    });
                }
            })
            // При уходе курсора мышки с элемента, скрываем его
            .mouseout(function () {
                numTooltip.css({ display: 'none' });
            });
        }
    }
})(window);

Теперь, для добавления автоматической нумерации во всплывающем окне, достаточно вызвать функцию "window.numTipTable.num".

Одной из частей, которую хотелось отметить отдельно, это набор параметров, который передается в функцию "num"

        ////////////////////////////////////
        // function num
        ////////////////////////////////////
        // table - селектор или элемент таблицы
        // options: { - передаваемые параметры
        //  pos - позиция всплывающего окна относительно строки в таблице 
        //        (left, top, right, bottom)
        //  align - при отображении окна сверху или снизу, указывает его месторасположение по горизонтали
        //         (left, center, right)
        //  valign - при отображении окна справа или слева, указывает его месторасположение по вертикали
        //         (top, center, bottom)
        //  filter - селектор для выбора нужных строк 
        //        (применяется в случае, если используется скрытые строки в таблице, чтобы исключить их из выборки)
        //  start - номер первого элемента 
        //        (по умолчанию 1)
        // }
        ////////////////////////////////////

Как видите, кроме возможности задать стартовый номер и выбрать позицию всплывающего окна относительно строки, существует такой параметр, как "filter", который позволяет учитывать только нужные строки. Например, если вы используете скрытые строки для хранения данных или отображения данных по какому-либо событию, то, скорее всего, их не имеет смысл нумеровать. И вы можете отфильтровать их, задав этот фильтр. Параметр представляет собой обычный селектор для jQuery.

Еще одной особенностью, которую необходимо отметить - это обязательность использования тега tbody внутри таблицы. Связано это с тем, что формально по спецификации такой тэг должен присутствовать и некоторые браузеры автоматически добавляют его, при отсутствии. Делается это по той причине, что таблицы могут иметь сложную структуру. Например, таблицы, внутри строк которых отображаются другие таблицы. Поэтому, перед использованием скрипта обязательно убедитесь, что в таблице есть такой тэг. 

Примечание: Кроме того, не стоит надеется только на возможности браузеров. Использование корректных структур - это хорошая практика, которая убережет вас от массы возможных проблем. Помните, что если ваш браузер отобразил html-код так, как вам надо, то это еще не говорит о том, что он составлен корректно, и что в других браузерах у вас не возникнет проблем или что, при использовании сторонних скриптов, не возникнут ошибки. 

 

Тестовая страница с таблицей - index.html 

Тестовая страница достаточно проста и содержит только таблицу, для которой будет вызываться скрипт автоматической нумерации данных. 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
        <link href="/css/template.css" rel="stylesheet" type="text/css"/>
 
        <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
        <script src="/js/jquery-numtiptable.js"></script>
    </head>
 
    <script type=text/javascript>
        $(function () {
            // Наполняем таблицу строками
            for (var i = 0; i < 30; i++) {
                $('.num-table tbody')
                .append('<tr>' 
                        + '<td>' + (new Date()).toLocaleDateString() + ' ' + (new Date()).toLocaleTimeString() + '</td>'
                        + '<td>' 
                            + 'Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст ' 
                            + 'Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст ' 
                        + '</td>'
                        + '<td>' + i*i + '</td>'
                        + '<td>' + 'Текст' + '</td>'
                    + '</tr>');
            }
            
            // Добавляем автоматическую нумерацию строк
            window.numTipTable.num('.num-table');
        });
    </script>
 
    <body>
        <h1>Нумерация строк таблицы во всплывающем окне средствами jquery</h1>
        <br/>
        <table class="num-table">
            <thead>
                <tr>
                    <th>Заголовок 1</th>
                    <th>Заголовок 2</th>
                    <th>Заголовок 3</th>
                    <th>Заголовок 4</th>
                </tr>
            </thead>
            <tbody>
                
            </tbody>
        </table>
    </body>
</html>

Как видите, ничего сложного нет. 

Теперь, сохраняем проект и смотрим результат, то есть открываем index.html в любом браузере.

 

Смотрим результат и пример использования

Примечание: Прежде, чем приступать к использованию еще раз оговоримся, что внутри таблицы, к которой будет применяться скрипт должен быть тэг "tbody". В противном случае, скрипт не выполнится корректно. Сделано это для того, чтобы скрипт можно было применять на таблицах со сложной структурой. Например, для таблиц, в ячейках которых отображаются другие таблицы.

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

Смотрим пример использования

После открытия тестового проекта, достаточно навести курсор мышки на любую строку, и рядом с ней появится небольшое всплывающее окно с номером текущей строки, как показано на рисунке ниже:

Пример использования автоматической нумерации во всплывающем окне средствами jQuery 

 

Возможные позиции всплывающего окна

Всего скрипт предусматривает 12 возможных позиций (по 3 на каждую сторону) для отображения всплывающего окна, как показано на рисунке ниже:

Возможные позиции всплывающего окна в скрипте автоматической нумерации строк

Как уже говорилось ранее в главе "Реализации скрипта", месторасположение всплывающего окна передается через параметр опции:

        ////////////////////////////////////
        // function num
        ////////////////////////////////////
        // table - селектор или элемент таблицы
        // options: { - передаваемые параметры
        //  pos - позиция всплывающего окна относительно строки в таблице 
        //        (left, top, right, bottom)
        //  align - при отображении окна сверху или снизу, указывает его месторасположение по горизонтали
        //         (left, center, right)
        //  valign - при отображении окна справа или слева, указывает его месторасположение по вертикали
        //         (top, center, bottom)
        //  filter - селектор для выбора нужных строк 
        //        (применяется в случае, если используется скрытые строки в таблице, чтобы исключить их из выборки)
        //  start - номер первого элемента 
        //        (по умолчанию 1)
        // }
        ////////////////////////////////////

Если вы не читали главу "Реализация скрипта", то повторимся про параметр "filter". Этот параметр применяется в тех случаях, когда в таблице есть скрытые строки, которые не должны нумероваться. К примеру, если за каждой строкой идет скрытая строка с информацией, которая отображается только при определенных действиях. Сам параметр представляет из себя простой селектор, который применяется к строкам таблицы, так что если вы уже не раз использовали jQuery, то всегда сможете легко его использовать.

 

Проверяем выполнены ли пункт реализации

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

  • Решение должно использовать js/jQuery и быть простым. Выполнено. Итоговое решение простое и понятное. Использует только стандартные возможности js/jQuery. Код простой и легко модифицируемый.
  • Должны решаться все указанные вначале статьи нюансы. Выполнено
    • Ширина таблицы не меняется
    • Можно указать стартовый номер строки
    • Лишние данные не передаются
    • Для перенумерации строк достаточно вызвать функцию повторно.
    • Решение использовать очень просто. Достаточно вызывать функцию после каждого изменения таблицы.
  • Возможность указывать позицию всплывающего окна. Выполнено. Скрипт поддерживает 12 возможных позиций.

Как видите, скрипт получился достаточно простой и реализующий все необходимые возможности.

Исходный проект вы можете скачать тут:

NumTipTable.zip 

Рубрики:
1 1 1 1 1 1 1 1 1 1 Рейтинг 1.00 (1 Голос)

Добавить комментарий / отзыв

Комментарий - это вежливое и наполненное смыслом сообщение (правила).


Введите защитный код

Обновить
Защитный код

Каталог программ