Главная
>>
Каталог задач
>>
Большие объемы данных
>>
Постраничный вывод
Aвтор:
this
Дата:
14.07.2004
Просмотров: 74160
реализации(php: 4шт...)
+добавить
Введение
Очень распрастраненная задача, как в прикладном, так и в веб- программировании. Хотя в последнем случае - наверное все же ее приходится решать чаще...
Допустим имеется страница с таблицей(гридом и проч.), где нужно выводить огромное количество строк с однотипными данными. Например, этих однотипных элементов - несколько тысяч. Выводить все на одной странице(в одной форме) - довольно неразумно: и пользователю будет трудно воспринимать все это и технически рендеринг/вырисовывание всех этих строк - может занять довольно продолжительное время в зависимости от скорости компьютера пользователя:
data1 |
data2 |
data3 |
............. |
dataN |
data21 |
data22 |
data23 |
............. |
data2N |
data31 |
data32 |
data33 |
............. |
data3N |
.. .. .. ..... здесь еще сотни таких строк.. .. ... |
dataM1 |
dataM2 |
dataM3 |
............. |
dataMN |
Логичное и самое правильное решение - разбить эту таблицу на несколько страниц, а внизу поставить ссылки(кнопки) переключения на другие страницы.
Формализация
Формализуем задачу.
На входе имеем:
- Суммарное количество доступных для просмотра объектов(N)
- Максимальное число объектов, которое может отображаться пользователю на одной странице(perPage)
- Id страницы, которую нужно отобразить на данный момент. Обычно это либо просто порядковый номер (currPageNum) данной страницы, начиная с 1-ой, либо смещение(currOffset), показывающее сколько объектов нужно пропустить.
На выходе нужно получить список страниц рассмотрев различные варианты, например:
- Простой список номеров всех страниц с выделение номера(7) текущей страницы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- Вариант №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
- Расширенный список, отображающий номера страниц, только близлежащие с номером текущей просматриваемой страницы(в пределах некоторого настраиваемого диапазона конечно) +ссылки "предыдущая" и "следующая" страницы:
предыдущая(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 как заблагорассудится.
- Вариант 3 +отображение номера первой и последней страницы:
предыдущая(6) 1 ... 5 6 7 8 9 ... 15 следующая(8)
Рассмотрим каждый из вариантов в отдельности. При этом в качестве 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.
Реализации:
php(4)
+добавить
1)
Простой список на php, code #84[автор:this]
<!-- Отображение пострачного вывода -->
<?php
$N = 145;
$perPage = 10;
$currOffset = 70;
if (isset($_GET['st'])) $currOffset =
$_GET['st'];
$currNum = 0;
for ($i = 0; $i < $N; $i += $perPage) {
$currNum++;
if ($i == $currOffset) {
print ' <b>'.
$currNum.
'</b> ';
} else {
print ' <a href="?st='.
$i.
'">'.
$currNum.
'</a> ';
}
}
?>
<!-- Отображение данных(объектов) текущей страницы -->
<b>Объекты</b>:<br>
<?php
$end = $currOffset + $perPage;
if ($end > $N) $end = $N;
for ($i = $currOffset; $i < $end; $i++) {
}
?>
2)
Простой список +предыдущая/следущая страницы на php, code #85[автор:this]
<!-- Отображение пострачного вывода -->
<?php
$N = 145;
$perPage = 10;
$currOffset = 70;
if (isset($_GET['st'])) $currOffset =
$_GET['st'];
$currNum = 0;
$prevOffset = -1; // Смещение для ссылки "предыдущая" страница
if ($currOffset - $perPage >= 0) $prevOffset = $currOffset - $perPage;
$nextOffset = 0; // Смещение для ссылки "следующая" страница
if ($currOffset + $perPage < $N) $nextOffset = $currOffset + $perPage;
if ($prevOffset >= 0) {
print ' <a href="?st='.
$prevOffset.
'">Предыдущая страница</a> ';
}
for ($i = 0; $i < $N; $i += $perPage) {
$currNum++;
if ($i == $currOffset) {
print ' <b>'.
$currNum.
'</b> ';
} else {
print ' <a href="?st='.
$i.
'">'.
$currNum.
'</a> ';
}
}
if ($nextOffset) {
print ' <a href="?st='.
$nextOffset.
'">Следующая страница</a> ';
}
?>
<!-- Отображение данных(объектов) текущей страницы -->
<b>Объекты</b>:<br>
<?php
$end = $currOffset + $perPage;
if ($end > $N) $end = $N;
for ($i = $currOffset; $i < $end; $i++) {
}
?>
3)
Расширенный список на php, code #86[автор:this]
<!-- Отображение пострачного вывода -->
<?php
$N = 145;
$perPage = 10;
$currOffset = 70;
if (isset($_GET['st'])) $currOffset =
$_GET['st'];
// Количество соседних номеров страниц с каждой стороны,
// отображающихся рядом с текущей страницей
$xwidth = 3;
$currNum = 0;
$prevOffset = -1;
if ($currOffset - $perPage >= 0) $prevOffset = $currOffset - $perPage;
$nextOffset = 0;
if ($currOffset + $perPage < $N) $nextOffset = $currOffset + $perPage;
if ($prevOffset >= 0) {
print ' <a href="?st='.
$prevOffset.
'">Предыдущая страница</a> ';
}
// Флаги вывода левого и правого многоточия
$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 == $currOffset) {
print ' <b>'.
$currNum.
'</b> ';
} else {
print ' <a href="?st='.
$i.
'">'.
$currNum.
'</a> ';
}
}
if ($nextOffset) {
print ' <a href="?st='.
$nextOffset.
'">Следующая страница</a> ';
}
?>
<!-- Отображение данных(объектов) текущей страницы -->
<b>Объекты</b>:<br>
<?php
$end = $currOffset + $perPage;
if ($end > $N) $end = $N;
for ($i = $currOffset; $i < $end; $i++) {
}
?>
4)
Расширенный список + первая/последняя страницы на php, code #87[автор:this]
<!-- Отображение пострачного вывода -->
<?php
$N = 145;
$perPage = 10;
$currOffset = 70;
if (isset($_GET['st'])) $currOffset =
$_GET['st'];
// Количество соседних номеров страниц с каждой стороны,
// отображающихся рядом с текущей страницей
$xwidth = 2;
$currNum = 0;
$prevOffset = -1;
if ($currOffset - $perPage >= 0) $prevOffset = $currOffset - $perPage;
$nextOffset = 0;
if ($currOffset + $perPage < $N) $nextOffset = $currOffset + $perPage;
if ($prevOffset >= 0) {
print ' <a href="?st='.
$prevOffset.
'">Предыдущая страница</a> ';
}
// Флаги вывода левого и правого многоточия
$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 == $currOffset) {
print ' <b>'.
$currNum.
'</b> ';
} else {
print ' <a href="?st='.
$i.
'">'.
$currNum.
'</a> ';
}
}
if ($nextOffset) {
print ' <a href="?st='.
$nextOffset.
'">Следующая страница</a> ';
}
?>
<!-- Отображение данных(объектов) текущей страницы -->
<b>Объекты</b>:<br>
<?php
$end = $currOffset + $perPage;
if ($end > $N) $end = $N;
for ($i = $currOffset; $i < $end; $i++) {
}
?>