Бесконечная страница

Бесконечная страница: динамическая загрузка контента на WordPress

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

В общем, полный код бесконечной страницы(уже посаженой на шаблон страницы вордпрес) можно увидеть и взять здесь.

Добавить комментарий

Ваш адрес email не будет опубликован.