Постепенная загрузка страницы на jquery. Улучшаем «бесконечный скроллинг. Подгрузка внешних данных
Сколько я себя помню, веб-разработчики всегда обращались к старой-доброй пагинации в случае, когда им необходимо было отобразить большое количество контента. Не поймите меня неправильно, пагинация до сих пор является эффективным способом отображения контента, но в этой статье мы поговорим о другом подходе - “ленивой” прокрутке, также известной под названием “бесконечной прокрутки” и “отказом от пагинации”. С помощью этой техники подгрузка контента производится с помощью AJAX, когда пользователь прокручивает страницу до места, где загруженный контент заканчивается. Ленивая прокрутка используется некоторыми гигантами интернета, такими как Facebook и Pinterest. В этом посте мы попробуем реализовать свой плагин для ленивой загрузки на jQuery.
Преимущества и недостаткиПреимущества такого метода очевидны. Для того, чтобы получить дополнительную порцию контента вам нет необходимости переходить на другую страницу, что также сбивает ваше внимание и заставляет смотреть в другую область страницы. Добавив возможность ленивой загрузки вы удерживаете внимание пользователя на одной и той же области в процессе чтения.
Ленивая загрузка эффективна не во всех ситуациях. Например, в случаях, когда пользователь переходит по ссылке, а затем хочет вернуться на предыдущую страницу с помощью истории браузера, он теряет позицию в той части, которая была подгружена с помощью AJAX. Одним из способов решения подобной проблемы - открывать все ссылки в новом окне или вкладке.
В добавок, перед тем, как решите использовать эту технологию знайте, что поисковые системы не очень-то дружны с такими решениями. Для того, чтобы избежать проблемы видимости контента поисковикам, убедитесь, что вы можете предоставить альтернативу с пагинацией или картой сайта.
НачинаемНачнем с наброска очень простой страницы. Самые важные части страницы показаны в коде ниже. Полные файлы можно посмотреть в исходниках.
HTMLПривет! Я - первый элемент Привет! Я - второй элемент Привет! Я - третий элемент Итак, это становится скучным... Попробуем кое-что новенькое Как насче того, чтобы загрузить еще элементов посредством AJAX Нажмите на кнопку ниже, чтобы загрузить больше элементов загрузить еще загружаю дополнительные элементы
CSS#data-container { margin: 10px; } #data-container .data-item { background-color: #444444; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px; margin: 5px; color: #fff; } #loading-div { display: none; } #button-more{ cursor: pointer; margin: 0 auto; background-color: #aeaeae; color: #fff; width: 200px; height: 50px; line-height: 50px; }
Основные замечанияЕсли вы приглядитесь к документу, что мы создали, то увидите, что новые посты будут загружены при клике на кнопку “загрузить еще”. Вот пункты, которые мы будем реализовывать:
- необходимо сделать запрос на URL, который вернет нам список элементов, которые необходимо будет вставить на странице
- этот процесс должен повторяться каждый раз, как будет нажата кнопка, но в результате должны возвращаться новые посты
- новые посты должны выдаваться на каждый запрос до тех пор, пока есть, что возвращать
- когда больше не осталось постов, необходимо сообщить пользователю, что он достиг конца
В идеале необходимо объявить переменную, в которой мы будем хранить номер страницы, и с помощью этого номера определять URL, на который мы будем отправлять запрос. В нашем демонстрационном примере у нас будут три таких страницы: 2.html, 3.html и пустая страница 4.html.
Когда вы нажимаете на кнопку загрузки следующей порции данных, проходит некоторое время от момента отправки запроса и получения ответа. В таком случае мы будем прятать кнопку загрузки, а вместо нее будем показывать некоторый текст, говорящий о том, что идет загрузка элементов:
Добавляем полученные данные на страницуСначала вернем обратно те изменения, которые мы проделали, пока запрос еще выполнялся, то есть, показать кнопку “загрузить еще”, и спрятать информационный текст. Во-вторых, необходимо вставить полученные данные на страницу, после тех элементов, что уже есть на странице. Заметьте, что для упрощения в этом примере мы получаем данные HTML сразу, как результат запроса. Можно отсылать ответ в формате JSON, добавив в него дополнительные переменные, как статус или сообщение. Код ставки данных представлен ниже:
$(buttonId).show(); $(loadingId).hide(); $(response).appendTo($(container)); page += 1;
Обрабатываем вариант, когда данные закончилисьКак только вы достигнете последнего поста, вам нужно показать пользователю, что больше постов нет. Сделать это можно различными способами. Можно отсылать статус в виде встроенного в ответ кода или сообщения. Так как мы напрямую используем разметку HTML в этом примере, то пустой ответ в нашем случае будет говорить о том, что данные закончились.
$.ajax({ ... success: function(response) { // Действие при пустом ответе if (response.trim() == "") { $(buttonId).fadeOut(); $(loadingId).text("No more entries to load!"); return; } // Если ответ верный }, ... });
ЗаключениеВ данном демонстрационном примере мы привели очень базовый вариант обработки ленивой загрузки. Конечно же, можно сделать гораздо лучше, если постараться. Для начала, можно вообще избавиться от кнопки, и отправлять запрос, когда пользователь прокрутит страницу до конца. Это избавит пользователя от дополнительной необходимости нажимать кнопку, и в целом ускоряет процесс просмотра информации. Во-вторых, можно просто отсылать чистые данные в формате JSON, а разметку создавать налету, используя jQuery, например:
$.each(response.items, function(index, value) { $("", { "class" : "data-item", "text" : value }); });
И, наконец, ответ в JSON может содержать сообщение, говорящее, прошел ли запрос корректно; данные; а также информацию о том, есть ли еще посты для загрузки. В данном случае это более эффективный способ отправлять результат.
Песочница
рекрут 9 февраля 2013 в 21:42 Крути меня полностью. Адаптивный макет с бесконечной прокруткой- Чулан *
Не так давно столкнулся с задачей:
- Верстка адаптивного макета. При ресайзе окна, элементы на странице масштабируются до определенной ширины. Если ширина меньше минимальной, количество элементов в ряду становится меньше, в то же время заполняя весь экран по ширине. Смысл понятен - страница должна смотреться на любом мониторе, в т.ч. на мобильных устройствах.
- Подгрузка содержимого происходит при прокрутке страницы, так что выводится лишь часть контента, остальной подгружается по мере прокрутки вниз (аналог стены ВК).
- Появление элементов на странице происходит по очереди, плавным увеличением прозрачности каждого элемента. После того как первый элемент стал непрозрачным, эффект применяется к следующему элементу… и так для всех.
Готового решения не нашел, все пришлось писать с нуля. Возможно вся эта фича бесполезна, но если вдруг кому пригодится - юзаем, тестируем, наслаждаемся:
HTML
. Для тестирования по-быстрому сверстал очень простой макет. Чтобы долго не заморачиваться со стилями, подключил bootstrap. Вот такая разметка:
Хеллоу ворлд!
// В принципе, инициализировать класс можно и не здесь, и без параметров. Об этом далее.
// контейнер, куда выводятся все элементы.
// В нашем случае каждый item - отдельный элемент на странице. Их выведем много.
// ... много-много item
// Делаем очистку, т.к. у наших item"ов float:left
CSS
. Тут все просто до безобразия. Подключил bootstrap, задал несколько стилей для контента - и вперед!
@import url("bootstrap.css");
body { background: #000; }
section.container { position: absolute; top: 50px; bottom: 50px; width: 100%; overflow: auto;}
section.container > section.item { position: relative; float: left; margin: 0; padding: 0; height: 140px; overflow: hidden;}
section.container > section.item > img {width: 100%;}
JS
. Вот тут уже интересно. Изначально писал функции по-отдельности, потом, когда все заработало обьединил их в один класс
GALLERY = {
// задаем дефолтные параметры, которые можно будет переопределить при инициализации.
container: "section.container", // родительский контейнер
item: "section.item", // отдельный элемент галереи
img: "section.item > img.hidden", // изображение, которое мы будем изначально "прятать"
interval: 200, // задержка эффекта прозрачности
count: 5, // количество добавляемых элементов
init: function(params) {
var _self = this;
// Переопределение параметров (если такие переданы. Если нет - используем по умолчанию.)
if(params != undefined){
for (var key in params) {
_self = params;
}
}
return _self.setUp();
},
setUp: function() {
var _self = this;
// Вешаем обработчики событий. В нашем случае такие нужны окну (ресайз)
$(window).bind("resize", function(){
_self.adjust();
});
// ... на загрузку страницы
$(document).ready(function(){
_self.adjust();
_self.play();
});
// ... на прокутку в родительском блоке
$(_self.container).bind("scroll", function(){
_self.checkScroll();
});
},
// подгоняем ширину и количество элементов в ряду, зависимо от размера окна
adjust: function() {
var _self = this;
var outWidth = $(_self.container).width();
var outHeight = $(_self.container).height();
var minWidth = 220;
var cnt = Math.floor(outWidth / minWidth);
var itemWidth = outWidth / cnt;
$(_self.item).css({
"width" : itemWidth + "px"
});
},
// Запускаем эффект постепенного появления элементов. Маленький нюанс: Класс hidden
// для изображения нужен не за тем чтобы его прятать (это будет делать метод ниже), а для поиска
// первого элемента при каждом обновлении контента. Цикл метода play() проходит
// по всем изображениям с классом hidden (изначально такой есть у всех), после применения
// эффекта fadeIn(), удаляя класс. Таким образом, при подгрузке нового контента, цикл начинается
// не с первого элемента, а с первого подгруженного.
// Впервые столкнулся с использованием метода queue().
play: function() {
var _self = this;
var items = $(_self.container).find(_self.img);
$(items).each(function(i) {
var cur = $(this).hide();
$(document).queue("myQueue", function(n) {
cur.removeClass("hidden").fadeIn(_self.interval, n);
});
});
$(document).dequeue("myQueue");
},
// Собственно подгрузка контента. Здесь все просто: отправляем запрос на сервер - получаем
// новое содержимое на страницу (если такое есть) и выводим его в самом конце родительского блока
load: function() {
var _self = this;
$.ajax({
url: "/load.php",
type: "POST",
data: {"count": _self.count},
dataType: "json",
success: function(json) {
if(json.output) {
$(_self.container).children("div.clearfix").before(json.output);
_self.adjust();
_self.play();
}
}
});
},
// Проверяем состояние прокрутки. Если вертикальная прокрутка в родительском блоке
// равна максимально возможной - отправляем запрос за новым контентом.
// Таким образом, подгрузка содержимого будет выполняться только если мы
// докрутили страницу до конца.
checkScroll: function() {
var _self = this;
var scrollH = $(_self.container).prop("scrollHeight");
var scrollT = $(_self.container).prop("scrollTop");
var scrollS = $(_self.container).prop("scrollTop") + $(_self.container).height();
if(scrollS == scrollH) {
_self.load();
}
}
}
PHP
. Тут все примитивно, только для тестирования.
$json = array();
$html = "";
$items_on_page = !empty($_POST["count"])? (int)$_POST["count"]: 5;
for($i = 0; $i < $items_on_page; $i++) {
$html .= "";
}
$json["output"] = $html;
echo json_encode($json);
Здесь в $_POST передается только один параметр (количество добавляемых блоков), но можно передать дополнительно точку старта, по принципу пагинации. Ее можно получить в JS при помощи:
var items = $(_self.container).find(_self.img);
var start = items.length;
// и передать в запросе:
data: {"count": _self.count, "start": start},
// ... после чего при выборке данных указать..." LIMIT " . (int)$_POST["start"] . ", " . $items_on_page;
Вот такая получилась «пагинация без пагинации», да на резиновой страничке. Рабочий пример здесь.
Сколько я себя помню, веб-разработчики всегда обращались к старой-доброй пагинации в случае, когда им необходимо было отобразить большое количество контента. Не поймите меня неправильно, пагинация до сих пор является эффективным способом отображения контента, но в этой статье мы поговорим о другом подходе - “ленивой” прокрутке, также известной под названием “бесконечной прокрутки” и “отказом от пагинации”. С помощью этой техники подгрузка контента производится с помощью AJAX, когда пользователь прокручивает страницу до места, где загруженный контент заканчивается. Ленивая прокрутка используется некоторыми гигантами интернета, такими как Facebook и Pinterest. В этом посте мы попробуем реализовать свой плагин для ленивой загрузки на jQuery.
Преимущества и недостаткиПреимущества такого метода очевидны. Для того, чтобы получить дополнительную порцию контента вам нет необходимости переходить на другую страницу, что также сбивает ваше внимание и заставляет смотреть в другую область страницы. Добавив возможность ленивой загрузки вы удерживаете внимание пользователя на одной и той же области в процессе чтения.
Ленивая загрузка эффективна не во всех ситуациях. Например, в случаях, когда пользователь переходит по ссылке, а затем хочет вернуться на предыдущую страницу с помощью истории браузера, он теряет позицию в той части, которая была подгружена с помощью AJAX. Одним из способов решения подобной проблемы - открывать все ссылки в новом окне или вкладке.
В добавок, перед тем, как решите использовать эту технологию знайте, что поисковые системы не очень-то дружны с такими решениями. Для того, чтобы избежать проблемы видимости контента поисковикам, убедитесь, что вы можете предоставить альтернативу с пагинацией или картой сайта.
НачинаемНачнем с наброска очень простой страницы. Самые важные части страницы показаны в коде ниже. Полные файлы можно посмотреть в исходниках.
HTMLПривет! Я - первый элемент Привет! Я - второй элемент Привет! Я - третий элемент Итак, это становится скучным... Попробуем кое-что новенькое Как насче того, чтобы загрузить еще элементов посредством AJAX Нажмите на кнопку ниже, чтобы загрузить больше элементов загрузить еще загружаю дополнительные элементы
CSS#data-container { margin: 10px; } #data-container .data-item { background-color: #444444; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px; margin: 5px; color: #fff; } #loading-div { display: none; } #button-more{ cursor: pointer; margin: 0 auto; background-color: #aeaeae; color: #fff; width: 200px; height: 50px; line-height: 50px; }
Основные замечанияЕсли вы приглядитесь к документу, что мы создали, то увидите, что новые посты будут загружены при клике на кнопку “загрузить еще”. Вот пункты, которые мы будем реализовывать:
- необходимо сделать запрос на URL, который вернет нам список элементов, которые необходимо будет вставить на странице
- этот процесс должен повторяться каждый раз, как будет нажата кнопка, но в результате должны возвращаться новые посты
- новые посты должны выдаваться на каждый запрос до тех пор, пока есть, что возвращать
- когда больше не осталось постов, необходимо сообщить пользователю, что он достиг конца
В идеале необходимо объявить переменную, в которой мы будем хранить номер страницы, и с помощью этого номера определять URL, на который мы будем отправлять запрос. В нашем демонстрационном примере у нас будут три таких страницы: 2.html, 3.html и пустая страница 4.html.
Когда вы нажимаете на кнопку загрузки следующей порции данных, проходит некоторое время от момента отправки запроса и получения ответа. В таком случае мы будем прятать кнопку загрузки, а вместо нее будем показывать некоторый текст, говорящий о том, что идет загрузка элементов:
Добавляем полученные данные на страницуСначала вернем обратно те изменения, которые мы проделали, пока запрос еще выполнялся, то есть, показать кнопку “загрузить еще”, и спрятать информационный текст. Во-вторых, необходимо вставить полученные данные на страницу, после тех элементов, что уже есть на странице. Заметьте, что для упрощения в этом примере мы получаем данные HTML сразу, как результат запроса. Можно отсылать ответ в формате JSON, добавив в него дополнительные переменные, как статус или сообщение. Код ставки данных представлен ниже:
$(buttonId).show(); $(loadingId).hide(); $(response).appendTo($(container)); page += 1;
Обрабатываем вариант, когда данные закончилисьКак только вы достигнете последнего поста, вам нужно показать пользователю, что больше постов нет. Сделать это можно различными способами. Можно отсылать статус в виде встроенного в ответ кода или сообщения. Так как мы напрямую используем разметку HTML в этом примере, то пустой ответ в нашем случае будет говорить о том, что данные закончились.
$.ajax({ ... success: function(response) { // Действие при пустом ответе if (response.trim() == "") { $(buttonId).fadeOut(); $(loadingId).text("No more entries to load!"); return; } // Если ответ верный }, ... });
ЗаключениеВ данном демонстрационном примере мы привели очень базовый вариант обработки ленивой загрузки. Конечно же, можно сделать гораздо лучше, если постараться. Для начала, можно вообще избавиться от кнопки, и отправлять запрос, когда пользователь прокрутит страницу до конца. Это избавит пользователя от дополнительной необходимости нажимать кнопку, и в целом ускоряет процесс просмотра информации. Во-вторых, можно просто отсылать чистые данные в формате JSON, а разметку создавать налету, используя jQuery, например:
$.each(response.items, function(index, value) { $("", { "class" : "data-item", "text" : value }); });
И, наконец, ответ в JSON может содержать сообщение, говорящее, прошел ли запрос корректно; данные; а также информацию о том, есть ли еще посты для загрузки. В данном случае это более эффективный способ отправлять результат.
Что-то давненько я не публиковал никакого кода. Сегодня я исправлю ситуацию и дам несколько полезных сниппетов на jQuery, которые обязательно вам пригодятся на ваших сайтах.
Я не буду вдаваться в теорию, вся документация по jQuery есть на официальном сайте библиотеки. Я лишь напомню, что, такое jQuery.
jQuery - это библиотека JavaScript, фокусирующаяся на взаимодействии JavaScript и HTML. Библиотека jQuery помогает легко получать доступ к любому элементу DOM, обращаться к атрибутам и содержимому элементов DOM, манипулировать ими. Также библиотека jQuery предоставляет удобный API для работы с AJAX.
Итак, поехали!
1. Плавная прокрутка к началу страницыБез нее уже не обходится ни один сайт. Всего лишь 4 строчки кода позволят вашим посетителям в один клик плавно пркрутить всю страницу вверх.
$("a").click(function() { $("html, body").animate({ scrollTop: 0 }, "slow"); return false; });
2. Дублируем заголовки таблицЧтобы улучшить восприятие и читабельность ваших таблиц, можно продублировать их заголовки снизу под таблицей. Казалось бы мелочь, но это очень удобно в сложных и больших таблицах, которые не умещаются в один экран.
Var $tfoot = $(""); $($("thead").clone(true, true).children().get().reverse()).each(function(){ $tfoot.append($(this)); }); $tfoot.insertAfter("table thead");
3. Подгрузка внешних данныхС помощью jQuery очень легко подгружать на веб-страницы внешний контент. Его можно вывести прямо в блок DIV, как в примере ниже.
$("#content").load("somefile.html", function(response, status, xhr) { // error handling if(status == "error") { $("#content").html("An error occured: " + xhr.status + " " + xhr.statusText); } });
4. Одинаковая высота колонокИзвестно, что выровнять блоки по высоте стандартными средствами HTML и CSS не так-то просто. Всего несколько строк кода ниже позволит вам сделать высоту всех блоков равной высоте большего блока.
var maxheight = 0; $("div.col").each(function(){ if($(this).height() > maxheight) { maxheight = $(this).height(); } }); $("div.col").height(maxheight); 5. Табличная зебраКак известно, восприятие и читабельность таблицы будет заметно выше если сделать разноцветное чередование строк. Это очень легко реализуется на jQuery.
$(document).ready(function(){ $("table tr:even").addClass("stripe"); });
6. Частичное обновление страницыС помощью jQuery очень просто реализовать блочное (частичное) обновление страницы. К примеру, код ниже позволит вам каждые 10 секунд автоматически обновлять блок #refresh.
SetInterval(function() { $("#refresh").load(location.href+" #refresh>*",""); }, 10000); // milliseconds to wait
7. Предзагрузка изображенийДанный код позволяет осуществлять загрузку изображений в фоновом режиме без подгрузок в процессе просмотра страницы. Просто перечислите в 7 строке необходимые вам для предзагрузки изображения.
$.preloadImages = function() { for(var i = 0; i maxWidth){ ratio = maxWidth / width; $(this).css("width", maxWidth); $(this).css("height", height * ratio); height = height * ratio; } var width = $(this).width(); var height = $(this).height(); if(height > maxHeight){ ratio = maxHeight / height; $(this).css("height", maxHeight); $(this).css("width", width * ratio); width = width * ratio; } }); //$("#contentpage img").show(); // IMAGE RESIZE });
12. Подгрузка контента при прокрутке страницу внизЧаще этот прием называют как бесконечный скролл. Контент подгружается по мере прокрутки пользователем страницы. Это достаточно просто реализовать с помощью кода ниже.
Var loading = false; $(window).scroll(function(){ if((($(window).scrollTop()+$(window).height())+250)>=$(document).height()){ if(loading == false){ loading = true; $("#loadingbar").css("display","block"); $.get("load.php?start="+$("#loaded_max").val(), function(loaded){ $("body").append(loaded); $("#loaded_max").val(parseInt($("#loaded_max").val())+50); $("#loadingbar").css("display","none"); loading = false; }); } } }); $(document).ready(function() { $("#loaded_max").val(50); });
13. Проверка загрузки изображенияЧасто бывает нужно проверить загружено изображение в данный момент или нет. И в этом снова нам поможет jQuery.
Var imgsrc = "img/image1.png"; $("").load(function () { alert("image loaded"); }).error(function () { alert("error loading image"); }).attr("src", imgsrc);
14. Сортировка по-алфавитуЕсли вам нужна динамическая сортировка списка по-алфавиту, вам обязательно поможет этот небольшой сниппет.
$(function() { $.fn.sortList = function() { var mylist = $(this); var listitems = $("li", mylist).get(); listitems.sort(function(a, b) { var compA = $(a).text().toUpperCase(); var compB = $(b).text().toUpperCase(); return (compA < compB) ? -1: 1; }); $.each(listitems, function(i, itm) { mylist.append(itm); }); } $("ul#demoOne").sortList(); });
Сохраните - пригодится.
Всё самое новое и интересное из мира Вордпресс в моём Телеграм-канале . Подписываемся!