Все чаще и чаще на в сайты интегрируют элементы SPA, в частности “бесконечную страницу”… здравствуй, читатель! По ходу этой статьи будет описан принцип работы такой страницы, реализация и посадка на вордпресс.
SPA и бесконечная страница
В принципе, и SPA(Single Page Application – одно-страничное приложение) и бесконечная страница исповедуют один и тот же принцип(извиняюсь за тавтологию) – динамическая загрузка контента. Все очень просто – когда поступает событие(клик либо скролл, либо еще что-то), javascript’ом загружается новая порция контента и вставляется в страницу.
Реализация
Использовать буду jQuery(тут часть любителей хайповых React, Vue и прочего, вышли…). Обьясню свой выбор – зачем перегружать страницу яваскриптом? да, jQuery тоже библиотека без которой можно обойтись, но если он используется для многих других элементов – почему бы и нет?
Вот примерная разметка, составленная мной
<div class="container">
<div class="page-1">
<div class="card">
<img src="path/to/img-1" class="img-fluid">
<a href="path/to/single-post-1">
<h2>Post Title 1</h2>
</a>
<p>post 1 excerpt</p>
</div>
***
</div>
<div class="page-2"></div>
***
<template id="post">
<div class="card">
<img src="" alt="" class="img-fluid">
<a href="">
<h2></h2>
</a>
</div>
</template>
</div>Немного о ней: поскольку я черпать контент буду в ворпрессе – то и использую пагинацию для разбивки на загружаемые блоки. Первую страницу загрузим обычным способом(каждая страница – это div class="page-%n"). В теге template будет содержаться разметка нашего поста – после загрузки пачки постов я буду ее клонировать.
Далее, нужно прибегнуть к javascript. Как я говорил ранее, на странице будет jQuery, поэтому сделаем AJAX-запрос к WP REST API со списком постов и их данными. Но прежде – определим условия для начала загрузки постов. Раз уж бесконечное полотно – значит условие это достижение нижней границы текущей страницы
var prevScroll = 0,
page = 1,
windowH = $(window).height(),
positionY = $('.page-1').offset().top,
blockH = $('.page-1').height(),
template = $('#post').html(),
currentScroll, tmpl
$(window).scroll(function (event) {
currentScroll = $(this).scrollTop()
if (currentScroll > prevScroll) {
prevScroll = currentScroll
if (Math.round(blockH + positionY) === (windowH + currentScroll)) {
// Получаем посты, рисуем их и высчитываем новую границу для загрузки
}
}
})Немного пояснений для этого куска кода. Эта строка(12) позволяет отсеять скролл вверх; можно было б отслеживать прокрутку колеса на мишке – но тогда скрипт был бы мертв на мобильниках. По поводу Math.round() свойства – высота(как и ширина) может быть дробной, в то время как значение скролла всегда целое число. Еще замечу – этот скрипт рабочий только в случаи если под блоком(не по разметке, а по позиции) с постами нет больше блоков(отсутствует футер). Дело в том, что при быстрой прокрутке scrollTop() имеет разрывы и тогда может произойти перескок нужного значения – потому, заменим его(===) простым сравниванием(>). Также, поскольку загрузка постов требует времени, используем коэффициент(что пользователю не пришлось ждать и он не покинул из-за этого сайт). В итоге, строка 15 трансформируется в
if (0.8 * (blockH + positionY) < (windowH + currentScroll)) {Теперь, перейдем к тому, что внутри блока – содержимому строки 15. Само собой там загрузка и оттрисовка постов, но не только… вот полный код
$(window).off('scroll')
page++
$.get(
'/wp-json/wp/v2/posts',
{
per_page: 5,
page: page,
_embed: 'wp:featuredmedia'
},
function (response) {
$(response).each(function (i, e) {
tmpl = $(template).clone()
$(tmpl).find('img').attr('src', e._embedded["wp:featuredmedia"][0].source_url)
$(tmpl).find('a').attr('href', e.link)
$(tmpl).find('h2').text(e.title.rendered)
$(tmpl).append(e.excerpt.rendered)
$('.page-' + page).append(tmpl)
})
$('.page-' + page).find('img').on('load', function (i, e) {
positionY = $('.page-' + page).offset().top
blockH = $('.page-' + page).height()
})
if (page < pagesCount) {
$(window).on('scroll', onScroll)
}
}
)Традиционно, пояснения:
- строка 1 “убивает” прослушивание события прокрутки. Это нужно потому, что js асинхронен и способен отослать несколько одинаковых запросов к серверу – что, в свою очередь, приведет к повторению постов(помимо ненужной нагрузки на сервер);
- строки 4 – 33 сам запрос к серверу: первый аргумент это адрес эндпоинта WP REST API, который возвращает список постов, второй – обьект с параметрами постов, третий – функция, которая будет исполнена при получении ответа;
- строки 23 – 26 – почему измерения высоты блока заперты в load’е? – у меня нет контейнера с размерами для картинки, а поскольку они грузятся отдельно от аякса – они изменяют размер блока постов через некоторое время;
- строка 29 возвращаем прослушку прокрутки.
По ходу написания статьи я немного изменил скрипт, а именно, анонимную функцию слушателя присвоил переменной onScroll. Немного о том, почему в строке 14 я постоянно клонирую шаблончик – каждый клон одноразовый, т.е. один раз вставив клон его переменная стает пустой.
В общем, полный код бесконечной страницы(уже посаженой на шаблон страницы вордпрес) можно увидеть и взять здесь.