Создаем слайдер с изображением и текстом на React.js с нуля и оптимизируем

В этой статье я хочу затронуть задачу, с которой вы можете столкнуться на собеседовании на позицию Front-End — создание Image Slider.

За последние 5 месяцев у меня было 15 онсайт собеседований, а также офферы от Google, Roku, Microsoft и других. (Больше информации можно прочитать в моем Telegram-канале)

Вы должны реализовать этот виджет за ~45–50 минут и рассказать об оптимизации. Эту информацию я постараюсь рассказать здесь. Основная цель состоит не в том, чтобы реализовать Image Slider с большим количеством функционала, а в том, чтобы показать, как реализовать и оптимизировать.

Требования

Начнем с требований нашего виджета.

  • Показывать изображения с котиками из API с ограничением количества слайдов.
  • Показывать описание или заголовок для каждого изображения.
  • Навигация между слайдами с помощью стрелок.
  • Навигация на мобильных устройствах с помощью тача
  • Возможность перехода на любой слайд.
  • Автопроигрывание для слайдера.
  • Возможность настроить ширину и высоту слайдера.
  • Слайдер должен быть респонсив.
  • Изображения слайдера должны загружаться эффективно и отображаться как можно быстрее.

Макет

Рендеринг в браузере

Для первой и самой простой реализации мы выведем все слайды в браузере и будем показывать только часть во вьюпорте или в элементе слайдера (когда мы задаем ширину или высоту). Этот подход загружает все изображения для всех слайдов и имеет N DOM-элементов, где N — количество слайдов.

Архитектура компонентов

Код компонентов

Давайте начнем с пропсов нашего Slider-компонента. С помощью этоих пропсов мы можем конфигурировать наш слайдер.

{
   autoPlay: boolean,
   autoPlayTime: number,
   width: '%' | 'px',
   height: '%' | 'px',
}

В компоненте Slider нам нужно реализовать следующий функционал:

  • загружать изображения;
  • реализовать метод навигации по стрелкам;
  • реализовать метод навигации по точкам;
  • реализовать методы для навигации с помощью тача
  • функциональность автопроигрывания;
  • рендеринг слайдов, стрелок и точек.

Мы будем хранить текущий номер слайда и загруженные данные в локальном стейте компонента. Чтобы избежать большого количества прокидывания пропсов, предлагаю использовать Context для прокидывания методов навигации по слайдам и текущей информации о слайдере.https://embedd.srv.habr.com/iframe/62d06ee89c344d33ecf976f8https://embedd.srv.habr.com/iframe/62d06f01b8903d345d8f614b

Как вы можете видеть в архитектуре компонентов и коде, компонент Slider содержит 3 компонента: SlideList, Arrows и Dots.

У нас есть 2 стрелки слева и справа.https://embedd.srv.habr.com/iframe/62d06f33ab111334724405da

Для отображения стрелок с обеих сторон мы можем стилизовать их с помощью CSS.https://embedd.srv.habr.com/iframe/62d06f5482bb9f348992c5be

Мы знаем количество слайдов и можем отрендерить нужное количество точек.https://embedd.srv.habr.com/iframe/62d06f78d3d80a33fecd1ef1

Каждая точка выглядит следующим образом.https://embedd.srv.habr.com/iframe/62d06f8f93219833d70d16ec

Для отображения слайдов в SlideList мы можем получить элементы из контекста и визуализировать компонент Slide с ключами и данными о слайде.https://embedd.srv.habr.com/iframe/62d06fa9d3d80a33fecd1ef2

Для достижения такой анимации нужно использовать transform и translateX в стилях. Мы перемещаем наш контент на следующий слайд по номеру слайда в нашем массиве.

Компонент Slide содержит 2 компонента: SlideImage и SlideTitle. Эта архитектура позволяет добавлять новые функции на будущее для каждого слайда.https://embedd.srv.habr.com/iframe/62d06ffa6bb29b3416f407d1https://embedd.srv.habr.com/iframe/62d07009d5cd01344c92f134https://embedd.srv.habr.com/iframe/62d0701209459f343c8c1b37

Как оптимизировать решение?

Представьте, что у вас в слайдере много изображений и вам нужно его оптимизировать. Оптимизация зависит от анимации смены слайдов… да, анимации.

Я вижу здесь 2 пути оптимизации.

  • Отображение 3 слайдов одновременно.
  • Отображение только одного слайда за раз.

Давайте посмотрим на них.

Оптимизация с рендерингом 3-х слайдов

Если вы хотите использовать transform и translateX для смены слайдов, вы можете использовать следующую оптимизацию.

В этом решении рендерится только 3 слайда одновременно. Активный слайд посередине, предыдущий и следующий слайды. Это потому, что пользователь может нажимать на стрелки вперед или назад, или в случае автовоспроизведения мы каждый раз перемещаемся вперед. Это позволяет быстро показать контент пользователю.

Когда мы переходим к предыдущему или следующему слайду, мы вычисляем новые 3 слайда и рендерим их.

Оптимизация с рендерингом одного слайда

Если вы хотите использовать animation в CSS, вы можете использовать один слайд и каждый раз отображать один слайд с информацией.

Пример анимационных эффектов, которые можно применить.

Для этой оптимизации необходимо добавить некоторые изменения в коде.

Теперь нет необходимости использовать компонент SlidesList, мы должны рендерить только один компонент Slide (строка 99).

Также мы должны контролировать эффект анимации и применять его только при смене содержимого слайда (строка 41).

И последнее изменение, для быстрого отображения картинок пользователю мы должны предварительно загружать предыдущее и следующее изображения относительно текущего слайда (строка 25).https://embedd.srv.habr.com/iframe/62d070eeab111334724405db

В Slide нам нужно только одно изменение. Добавим функционал для класса с анимацией, когда запускается смена слайдов.https://embedd.srv.habr.com/iframe/62d07106d3d80a33fecd1ef3

Реализация анимации fadeIn в стилях.https://embedd.srv.habr.com/iframe/62d0711c3a1c1c33c7856c75

Другие оптимизации

  • Правильный размер изображения — нет необходимости использовать разрешение Full HD, если у вас слайдер с ограниченным размером и он меньше.
  • Использовать формат WebP для изображений — позволяет уменьшить размер изображений. Он сжимает как минимум на 20–30% лучше, чем jpg и png.
  • Не используйте изображения со 100-процентным качеством. Нет необходимости использовать изображения со 100-процентным качеством. По моему опыту, качество 70—85% выглядит так же, как и 100%, но размер изображения меньше.
  • Минимизируйте JavaScript и стили.
  • Используйте CDN для хранения изображений.
  • Используйте Brotli для сжатия – конечный размер данных меньше gzip на 14–21%.

Заключение

Не нужно обладать какими-то специальными знаниями, чтобы реализовать свой собственный слайдер изображений. Вам нужно попрактиковаться в этом без гугления и за ограниченное время.

Весь код вы можете найти на GitHub.