CodeLAB
на главную карта сайта обратная связь

Популярные задачи:

#Последовательный поиск и его оптимизации. (44870 hits)
#Улучшение быстрой сортировки. (77246 hits)
#qForms, библиотека типичного функционала валидации/построения/связки html-форм. (147672 hits)
#Рисование линии. (39005 hits)
#Таймер. (40975 hits)
#Относительный путь к файлу. (40028 hits)
#ООП на javascript: классы, наследование, инкапсуляция. (257902 hits)
#Разбор строки. (273622 hits)
#Сравнение алгоритмов сортировки массива. (182704 hits)
#Заполнение 2-го выпадающего списка (select) в соответствии с выбором в первом. (46488 hits)
#Преобразование сумм из цифрового представления в строковое. (176223 hits)
#Интерактивная, динамическая подгрузка картинок. (70076 hits)
#Выборка всех записей таблицы. (33710 hits)
#Курсы валют. (67702 hits)
#Шейкер-сортировка. (71559 hits)
#Вычисление эксцесса и коэффициентов асимметрии заданной выборки. (46072 hits)
#Простая геометрическая и текстовая анимация. (401186 hits)
#Код. (180370 hits)
#Подсветка синтаксиса. (31656 hits)
#Двусторонняя карта. (34271 hits)


Главная >> Каталог задач >> Большие объемы данных >> Постраничный вывод

Постраничный вывод

Aвтор:
Дата:
Просмотров: 72967
реализации(php: 4шт...) +добавить

Введение

Очень распрастраненная задача, как в прикладном, так и в веб- программировании. Хотя в последнем случае - наверное все же ее приходится решать чаще...

Допустим имеется страница с таблицей(гридом и проч.), где нужно выводить огромное количество строк с однотипными данными. Например, этих однотипных элементов - несколько тысяч. Выводить все на одной странице(в одной форме) - довольно неразумно: и пользователю будет трудно воспринимать все это и технически рендеринг/вырисовывание всех этих строк - может занять довольно продолжительное время в зависимости от скорости компьютера пользователя:

data1 data2 data3 ............. dataN
data21 data22 data23 ............. data2N
data31 data32 data33 ............. data3N
..
..
..
..... здесь еще сотни таких строк..
..
...
dataM1 dataM2 dataM3 ............. dataMN

Логичное и самое правильное решение - разбить эту таблицу на несколько страниц, а внизу поставить ссылки(кнопки) переключения на другие страницы.

Формализация

Формализуем задачу.

На входе имеем:

  1. Суммарное количество доступных для просмотра объектов(N)
  2. Максимальное число объектов, которое может отображаться пользователю на одной странице(perPage)
  3. Id страницы, которую нужно отобразить на данный момент. Обычно это либо просто порядковый номер (currPageNum) данной страницы, начиная с 1-ой, либо смещение(currOffset), показывающее сколько объектов нужно пропустить.

На выходе нужно получить список страниц рассмотрев различные варианты, например:

  1. Простой список номеров всех страниц с выделение номера(7) текущей страницы:
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  2. Вариант №1 +ссылки "предыдущая" и "следующая" страницы:
    предыдущая(6) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  следующая(8),
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  следующая(2),
    предыдущая(14) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  3. Расширенный список, отображающий номера страниц, только близлежащие с номером текущей просматриваемой страницы(в пределах некоторого настраиваемого диапазона конечно) +ссылки "предыдущая" и "следующая" страницы:
    предыдущая(6) ... 4 5 6 7 8 9 10 ... следующая(8),
    предыдущая(2) 1 2 3 4 5 6 ... следующая(4),
    предыдущая(13) ... 11 12 13 14 15  следующая(15)
    Поскольку страниц может быть тысячи, поэтому их перечисление будет занимать много места и вообще будет неудобным. Как видно, "настраиваемый диапазон" здесь - это 3 страницы до и 3 после. Конечно, с возможностью менять это число 3 как заблагорассудится.
  4. Вариант 3 +отображение номера первой и последней страницы:
    предыдущая(6) 1 ... 5 6 7 8 9 ... 15  следующая(8)

Рассмотрим каждый из вариантов в отдельности. При этом в качестве id страницы будем использовать смещение как наиболее простой и универсальный вариант.

Простой список

Самый простой соответсвенно алгоритм:

 псевдокод: Простой список  ссылка
  1. // Номер страницы(для пользователя)
  2. currNum = 0
  3. for i = 0; i < N; i += perPage
  4. currNum++
  5. if i == currOffset
  6. print currNum
  7. else
  8. // Выводим номер как ссылку на след.
  9. // страницу, определяя ее через новое
  10. // смещение, которое будет == i
  11. print currNum as <ref> where [offset=i]

 

Простой список +предыдущая и следущая страницы

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

 псевдокод: простой список +предыдущая и следующая страницы  ссылка
  1. // Рассчитываем смещение предыдущей страницы
  2. prevOffset = -1;
  3. if currOffset - perPage >= 0
  4. prevOffset = currOffset - perPage;
  5.  
  6. // Рассчитываем смещение для следующей страницы
  7. nextOffset = 0;
  8. if currOffset + perPage < N
  9. nextOffset = currOffset + perPage;
  10.  
  11. // Выводим ссылку(кнопку) на предыдущую страницу
  12. if prevOffset >= 0
  13. print "Previous Page" as <ref> where [offset=prevOffset]
  14.  
  15. // Номер страницы(для пользователя)
  16. currNum = 0
  17.  
  18. for i = 0; i < N; i += perPage
  19. currNum++
  20. if i == offset
  21. print currNum
  22. else
  23. // Выводим номер как ссылку на след.
  24. // страницу, определяя ее через новое
  25. // смещение, которое будет == i
  26. print currNum as <ref> where [offset=i]
  27.  
  28. // Выводим ссылку(кнопку) на следующую страницу
  29. if nextOffset > 0
  30. print "Next Page" as <ref> where [offset=nextOffset]

Обратите внимание на строчку 12: prevOffset вполне возможно может быть нулевым, что будет означать ссылку на первую страницу и будет иметь место при текущей странице - вторая страница.

Расширенный список

Здесь начинается самое интересное, поскольку в этом случае возникает уже довольно много вариантов "сокрытия" ненужных номеров страниц и регулировки этого диапазона сокрытия. Один из них может может выглядеть как:

 псевдокод: Расширенный список  ссылка
  1. // Количество соседних номеров страниц с каждой стороны,
  2. // отображающихся рядом с текущей страницей
  3. // Т.н. упомянутая "регулировка диапазона сокрытия"
  4. xwidth = 3;
  5.  
  6. // Рассчитываем смещение предыдущей страницы
  7. prevOffset = -1;
  8. if currOffset - perPage >= 0
  9. prevOffset = currOffset - perPage;
  10.  
  11. // Рассчитываем смещение для следующей страницы
  12. nextOffset = 0;
  13. if currOffset + perPage < N
  14. nextOffset = currOffset + perPage;
  15.  
  16. // Выводим ссылку(кнопку) на предыдущую страницу
  17. if prevOffset >= 0
  18. print "Previous Page" as <ref> where [offset=prevOffset]
  19.  
  20. // Номер страницы(для пользователя)
  21. currNum = 0
  22.  
  23.  
  24. // Флаги вывода левого и правого многоточия
  25. $leftBlankOut = $rightBlankOut = false;
  26.  
  27. for i = 0; i < N; i += perPage
  28. currNum++
  29.  
  30. // Манипулируем выводом левого многоточия
  31. if (i <= currOffset - xwidth * perPage - perPage)
  32. if (!leftBlankOut) print '...' // Вывод левого многоточия
  33. leftBlankOut = true
  34. continue
  35.  
  36. // Манипулируем выводом правого многоточия
  37. if (i >= currOffset + xwidth * perPage + perPage)
  38. if (!rightBlankOut) print '...' // Вывод правого многоточия
  39. rightBlankOut = true
  40. continue
  41.  
  42. if i == offset
  43. print currNum
  44. else
  45. // Выводим номер как ссылку на след.
  46. // страницу, определяя ее через новое
  47. // смещение, которое будет == i
  48. print currNum as <ref> where [offset=i]
  49.  
  50. // Выводим ссылку(кнопку) на следующую страницу
  51. if nextOffset > 0
  52. print "Next Page" as <ref> where [offset=nextOffset]


Как видим данный алгоритм позволяет легко настраивать дипазаон выводимых номеров вокруг текущего простым изменением переменной xwidth.

Расширеный список + первая и последняя страницы

Для этого нам потребуется внести лишь небольшие изменения в алгоритм предыдущего варианта:

 псевдокод: Расширенный список +первая и последняя страницы  ссылка
  1. // Количество соседних номеров страниц с каждой стороны,
  2. // отображающихся рядом с текущей страницей
  3. // Т.н. упомянутая "регулировка диапазона сокрытия"
  4. xwidth = 3;
  5.  
  6. // Рассчитываем смещение предыдущей страницы
  7. prevOffset = -1;
  8. if currOffset - perPage >= 0
  9. prevOffset = currOffset - perPage;
  10.  
  11. // Рассчитываем смещение для следующей страницы
  12. nextOffset = 0;
  13. if currOffset + perPage < N
  14. nextOffset = currOffset + perPage;
  15.  
  16. // Выводим ссылку(кнопку) на предыдущую страницу
  17. if prevOffset >= 0
  18. print "Previous Page" as <ref> where [offset=prevOffset]
  19.  
  20. // Номер страницы(для пользователя)
  21. currNum = 0
  22.  
  23.  
  24. // Флаги вывода левого и правого многоточия
  25. $leftBlankOut = $rightBlankOut = false;
  26.  
  27. for i = 0; i < N; i += perPage
  28. currNum++
  29.  
  30. // Манипулируем выводом левого многоточия
  31. if (i > 0) && (i <= currOffset - xwidth * perPage - perPage)
  32. if (!leftBlankOut) print '...' // Вывод левого многоточия
  33. leftBlankOut = true
  34. continue
  35.  
  36. // Манипулируем выводом правого многоточия
  37. if (i < N - perPage) && (i >= currOffset + xwidth * perPage + perPage)
  38. if (!rightBlankOut) print '...' // Вывод правого многоточия
  39. rightBlankOut = true
  40. continue
  41.  
  42. if i == offset
  43. print currNum
  44. else
  45. // Выводим номер как ссылку на след.
  46. // страницу, определяя ее через новое
  47. // смещение, которое будет == i
  48. print currNum as <ref> where [offset=i]
  49.  
  50. // Выводим ссылку(кнопку) на следующую страницу
  51. if nextOffset > 0
  52. print "Next Page" as <ref> where [offset=nextOffset]


Как видно по сравнению с предующим вариантом добавились лишь пара условий в строки 31 и 37.

Реализации:

php(4)   +добавить

1) Простой список на php, code #84[автор:this]
2) Простой список +предыдущая/следущая страницы на php, code #85[автор:this]
3) Расширенный список на php, code #86[автор:this]
4) Расширенный список + первая/последняя страницы на php, code #87[автор:this]