Разрабатывая любой проект часто приходиться сталкиваться с необходимостью создания постраничной навигации или как еще называют — пагинация. Будь-то список статей, пользователей или любые другие выборки с базы данных, где большое количество записей требуют лимитированного вывода. Такой вывод можно реализовать двумя способами:
1. Выгружать все данные и показывать пользователю только часть.
2. Выгружать только часть данных, которые непосредственно показывать.
Каждый из способов имеет свои плюсы и минусы, очевидно, если записей в базе очень много, то выгружая все, мы очень сильно нагружаем компьютер пользователя. Просто представьте, что при открытии страницы у вас подгружается 100.000 записей, с другой стороны, если выгрузка имеет только 100 элементов, то такой способ будет работать быстрее, так как не нужно постоянно обращаться к серверу.
В статье мы разберем второй способ, а именно выгрузку только тех данных, которые отдаются пользователю на текущей странице.
1. Функция pagePrint(), печатает ссылку на заданую страницу
function pagePrint($page, $title, $show, $active_class = '') { if($show) { echo '<a href="?do=list&page=' . $page . '">' . $title . '</a>'; } else { if(!empty($active_class)) $active = 'class="' . $active_class . '"'; echo '<span ' . $active . '>' . $title . '</span>'; } return false; }
$page — номер страницы;
$title — анкор ссылки (например, «1», «2», «10», «следующая»);
$show — показывать ссылку или текст, используется, чтобы вывести текущую страницу, или же неактивные ссылки «назад», «вперед»;
$active_class — класс CSS для активной страницы.
2. Начальный конфиг
$page_setting = [ 'limit' => 50, // кол-во записей на странице 'show' => 5, // 5 до текущей и после 'prev_show' => 0, // не показывать кнопку "предыдущая" 'next_show' => 0, // не показывать кнопку "следующая" 'first_show' => 0, // не показывать ссылку на первую страницу 'last_show' => 0, // не показывать ссылку на последнюю страницу 'prev_text' => 'назад', 'next_text' => 'вперед', 'class_active' => 'active', 'separator' => ' ... ', ]; $page = (int) $_GET['page']; if(empty($page)) $page = 1; // если страница не задана, показываем первую
3. Пример выборки данных из базы
$start = ($page-1)*$page_setting['limit']; $res = $db->query("SELECT * FROM table LIMIT {$start},{$page_setting['limit']}");
Для выборки используется LIMIT, где старт вычисляется по формуле (page-1)*limit, то есть для первой страницы start = 0.
4. Подсчет кол-ва страниц и проверка основных условий.
С подсчетом количества страниц иногда возникают проблемы, так как страниц может быть только целое число, а при делении (кол-во записей)/(лимит записей на странице) может получится дробное. Данный результат необходимо округлить в больную строну, потому что, обычное округление round(), выдаст ошибочный результат.
Пример, всего записей 31, на странице публикуем по 10, таким образом по формуле получается 3.1 страница, при округлении round(3.1) = 3, что неправильно, так как теряется одна запись. Поэтому используется функция ceil(), ceil(3.1) = 4.
$res = $db->query("SELECT count(*) AS count FROM dle_getmovie_movies {$where}"); $row = $res->fetch(PDO::FETCH_ASSOC); $page_count = ceil($row['count'] / $page_setting['limit']); // кол-во страниц $page_left = $page - $page_setting['show']; // находим левую границу $page_right = $page + $page_setting['show']; // находим правую границу $page_prev = $page - 1; // узнаем номер предыдушей страницы $page_next = $page + 1; // узнаем номер следующей страницы if($page_left < 2) $page_left = 2; // левая граница не может быть меньше 2, так как 2 - первое целое число после 1 if($page_right > ($page_count - 1)) $page_right = $page_count - 1; // правая граница не может ровняться или быть больше, чем всего страниц if($page > 1) $page_setting['prev_show'] = 1; // если текущая страница не первая, значит существует предыдущая if($page != 1) $page_setting['first_show'] = 1; // показываем ссылку на первую страницу, если мы не на ней if($page < $page_count) $page_setting['next_show'] = 1; // если текущая страница не последняя, значит существуюет следующая if($page != $page_count) $page_setting['last_show'] = 1;
5. Выводим на экран:
pagePrint($page_prev, $page_setting['prev_text'], $page_setting['prev_show']); pagePrint(1, 1, $page_setting['first_show'], $page_setting['class_active']); if($page_left > 2) echo $page_setting['separator']; for($i = $page_left; $i <= $page_right; $i++) { $page_show = 1; if($page == $i) $page_show = 0; pagePrint($i, $i, $page_show, $page_setting['class_active']); } if($page_right < ($page_count - 1)) echo $page_setting['separator']; if($page_count != 1) pagePrint($page_count, $page_count, $page_setting['last_show'], $page_setting['class_active']); pagePrint($page_next, $page_setting['next_text'], $page_setting['next_show']);
Вот и все, алгоритм разобран, ниже представлен код для вывода пагинации на Javascript:
// функция смены страницы function pageChange(page) { var page_show = 0; var page_txt = ''; var setting = page_setting(); setting.page_left = page - setting.show; // находим левую границу setting.page_right = page + setting.show; // находим правую границу setting.page_prev = page - 1; // узнаем номер предыдушей страницы setting.page_next = page + 1; // узнаем номер следующей страницы if(setting.page_left < 2) setting.page_left = 2; // левая граница не может быть меньше 2, так как 2 - первое целое число после 1 if(setting.page_right > (setting.page_count - 1)) setting.page_right = setting.page_count - 1; // правая граница не может ровняться или быть больше, чем всего страниц if(page > 1) setting.prev_show = 1; // если текущая страница не первая, значит существует предыдущая if(page != 1) setting.first_show = 1; // показываем ссылку на первую страницу, если мы не на ней if(page < setting.page_count) setting.next_show = 1; // если текущая страница не последняя, значит существуюет следующая if(page != setting.page_count) setting.last_show = 1; page_txt += pagePrint(setting.page_prev, setting.prev_text, setting.prev_show); page_txt += pagePrint(1, 1, setting.first_show, setting.class_active); if(setting.page_left > 2) page_txt += setting.separator; for(var i = setting.page_left; i <= setting.page_right; i++) { page_show = 1; if(page == i) page_show = 0; page_txt += pagePrint(i, i, page_show, setting.class_active); } if(setting.page_right < (setting.page_count - 1)) page_txt += setting.separator; if(setting.page_count != 1) page_txt += pagePrint(setting.page_count, setting.page_count, setting.last_show, setting.class_active); page_txt += pagePrint(setting.page_next, setting.next_text, setting.next_show); document.getElementById("pagenavi").innerHTML = page_txt; return false; } // функция для публикации ссылки на страницу function pagePrint(page, title, show, active_class = '') { if(show) { return '<a href="javascript:return false;" onclick="pageChange(' + page + ')">' + title + '</a>'; } else { var active = ''; if(active_class != '') active = 'class="' + active_class + '"'; return '<span ' + active + '>' + title + '</span>'; } return false; } var page = 1; // получаем номер страницы, для примера 1 if(page != undefined) page = 1; // если страница не задана, показываем первую var page_count = 10; // считаем кол-во страниц, для примера 10 // начальные настройки var page_setting = function() { return { 'limit': 50, // кол-во записей на странице 'show': 5, // 5 до текущей и после 'prev_show': 0, // не показывать кнопку "предыдущая" 'next_show': 0, // не показывать кнопку "следующая" 'first_show': 0, // не показывать ссылку на первую страницу 'last_show': 0, // не показывать ссылку на последнюю страницу 'prev_text': 'назад', 'next_text': 'вперед', 'class_active': 'active', 'separator': ' ... ', 'page_count': page_count, 'page_left': 0, 'page_right': 0, 'page_prev': 0, 'page_next': 0 } }; pageChange(page); // совершаем первый вызов
Остались вопросы — задаем в комментариях, также делимся своими наработками, если знаете как «красивее» реализовать пагинацию.
Может быть полезно