Все чаще и чаще на в сайты интегрируют элементы 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 я постоянно клонирую шаблончик — каждый клон одноразовый, т.е. один раз вставив клон его переменная стает пустой.
В общем, полный код бесконечной страницы(уже посаженой на шаблон страницы вордпрес) можно увидеть и взять здесь.