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