Очень распрастраненная задача, как в прикладном, так и в веб- программировании. Хотя в последнем случае - наверное все же ее приходится решать чаще...
Допустим имеется страница с таблицей(гридом и проч.), где нужно выводить огромное количество строк с однотипными данными. Например, этих однотипных элементов - несколько тысяч. Выводить все на одной странице(в одной форме) - довольно неразумно: и пользователю будет трудно воспринимать все это и технически рендеринг/вырисовывание всех этих строк - может занять довольно продолжительное время в зависимости от скорости компьютера пользователя:
data1 | data2 | data3 | ............. | dataN |
data21 | data22 | data23 | ............. | data2N |
data31 | data32 | data33 | ............. | data3N |
.. .. .. ..... здесь еще сотни таких строк.. .. ... |
||||
dataM1 | dataM2 | dataM3 | ............. | dataMN |
Логичное и самое правильное решение - разбить эту таблицу на несколько страниц, а внизу поставить ссылки(кнопки) переключения на другие страницы.
Формализуем задачу.
На входе имеем:
На выходе нужно получить список страниц рассмотрев различные варианты, например:
Рассмотрим каждый из вариантов в отдельности. При этом в качестве id страницы будем использовать смещение как наиболее простой и универсальный вариант.
Самый простой соответсвенно алгоритм:
// Номер страницы(для пользователя) currNum = 0 for i = 0; i < N; i += perPage currNum++ if i == currOffset print currNum else // Выводим номер как ссылку на след. // страницу, определяя ее через новое // смещение, которое будет == i print currNum as <ref> where [offset=i]
При этом следует учесть, что если текущая страница - первая или последняя из возможных, то логично будет не отображать ссылку на предыдущую или соответственно на следующую страницу:
// Рассчитываем смещение предыдущей страницы prevOffset = -1; if currOffset - perPage >= 0 prevOffset = currOffset - perPage; // Рассчитываем смещение для следующей страницы nextOffset = 0; if currOffset + perPage < N nextOffset = currOffset + perPage; // Выводим ссылку(кнопку) на предыдущую страницу if prevOffset >= 0 print "Previous Page" as <ref> where [offset=prevOffset] // Номер страницы(для пользователя) currNum = 0 for i = 0; i < N; i += perPage currNum++ if i == offset print currNum else // Выводим номер как ссылку на след. // страницу, определяя ее через новое // смещение, которое будет == i print currNum as <ref> where [offset=i] // Выводим ссылку(кнопку) на следующую страницу if nextOffset > 0 print "Next Page" as <ref> where [offset=nextOffset]
Обратите внимание на строчку 12: prevOffset вполне возможно может быть нулевым, что будет означать ссылку на первую страницу и будет иметь место при текущей странице - вторая страница.
Здесь начинается самое интересное, поскольку в этом случае возникает уже довольно много вариантов "сокрытия" ненужных номеров страниц и регулировки этого диапазона сокрытия. Один из них может может выглядеть как:
// Количество соседних номеров страниц с каждой стороны, // отображающихся рядом с текущей страницей // Т.н. упомянутая "регулировка диапазона сокрытия" xwidth = 3; // Рассчитываем смещение предыдущей страницы prevOffset = -1; if currOffset - perPage >= 0 prevOffset = currOffset - perPage; // Рассчитываем смещение для следующей страницы nextOffset = 0; if currOffset + perPage < N nextOffset = currOffset + perPage; // Выводим ссылку(кнопку) на предыдущую страницу if prevOffset >= 0 print "Previous Page" as <ref> where [offset=prevOffset] // Номер страницы(для пользователя) currNum = 0 // Флаги вывода левого и правого многоточия $leftBlankOut = $rightBlankOut = false; for i = 0; i < N; i += perPage currNum++ // Манипулируем выводом левого многоточия if (i <= currOffset - xwidth * perPage - perPage) if (!leftBlankOut) print '...' // Вывод левого многоточия leftBlankOut = true continue // Манипулируем выводом правого многоточия if (i >= currOffset + xwidth * perPage + perPage) if (!rightBlankOut) print '...' // Вывод правого многоточия rightBlankOut = true continue if i == offset print currNum else // Выводим номер как ссылку на след. // страницу, определяя ее через новое // смещение, которое будет == i print currNum as <ref> where [offset=i] // Выводим ссылку(кнопку) на следующую страницу if nextOffset > 0 print "Next Page" as <ref> where [offset=nextOffset]
Как видим данный алгоритм позволяет легко настраивать дипазаон выводимых номеров вокруг текущего простым изменением переменной xwidth.
Для этого нам потребуется внести лишь небольшие изменения в алгоритм предыдущего варианта:
// Количество соседних номеров страниц с каждой стороны, // отображающихся рядом с текущей страницей // Т.н. упомянутая "регулировка диапазона сокрытия" xwidth = 3; // Рассчитываем смещение предыдущей страницы prevOffset = -1; if currOffset - perPage >= 0 prevOffset = currOffset - perPage; // Рассчитываем смещение для следующей страницы nextOffset = 0; if currOffset + perPage < N nextOffset = currOffset + perPage; // Выводим ссылку(кнопку) на предыдущую страницу if prevOffset >= 0 print "Previous Page" as <ref> where [offset=prevOffset] // Номер страницы(для пользователя) currNum = 0 // Флаги вывода левого и правого многоточия $leftBlankOut = $rightBlankOut = false; for i = 0; i < N; i += perPage currNum++ // Манипулируем выводом левого многоточия if (i > 0) && (i <= currOffset - xwidth * perPage - perPage) if (!leftBlankOut) print '...' // Вывод левого многоточия leftBlankOut = true continue // Манипулируем выводом правого многоточия if (i < N - perPage) && (i >= currOffset + xwidth * perPage + perPage) if (!rightBlankOut) print '...' // Вывод правого многоточия rightBlankOut = true continue if i == offset print currNum else // Выводим номер как ссылку на след. // страницу, определяя ее через новое // смещение, которое будет == i print currNum as <ref> where [offset=i] // Выводим ссылку(кнопку) на следующую страницу if nextOffset > 0 print "Next Page" as <ref> where [offset=nextOffset]
Как видно по сравнению с предующим вариантом добавились лишь пара условий в строки 31 и 37.