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

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

У нас есть 2 стрелки слева и справа.

Для отображения стрелок с обеих сторон мы можем стилизовать их с помощью CSS.

Мы знаем количество слайдов и можем отрендерить нужное количество точек.

Каждая точка выглядит следующим образом.

Для отображения слайдов в SlideList мы можем получить элементы из контекста и визуализировать компонент Slide с ключами и данными о слайде.

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

Компонент Slide содержит 2 компонента: SlideImage и SlideTitle. Эта архитектура позволяет добавлять новые функции на будущее для каждого слайда.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

И последнее изменение, для быстрого отображения картинок пользователю мы должны предварительно загружать предыдущее и следующее изображения относительно текущего слайда (строка 25).

В Slide нам нужно только одно изменение. Добавим функционал для класса с анимацией, когда запускается смена слайдов.

Реализация анимации fadeIn в стилях.

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

  • Правильный размер изображения — нет необходимости использовать разрешение Full HD, если у вас слайдер с ограниченным размером и он меньше.

  • Использовать формат WebP для изображений — позволяет уменьшить размер изображений. Он сжимает как минимум на 20–30% лучше, чем jpg и png.

  • Не используйте изображения со 100-процентным качеством. Нет необходимости использовать изображения со 100-процентным качеством. По моему опыту, качество 70—85% выглядит так же, как и 100%, но размер изображения меньше.

  • Минимизируйте JavaScript и стили.

  • Используйте CDN для хранения изображений.

  • Используйте Brotli для сжатия - конечный размер данных меньше gzip на 14–21%.

Заключение

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

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

В следующих статьях я расскажу о виджете Tree View, виджете Star Rating, дизайне Google Doc и Google Sheets.

Удачи на собеседованиях!

Комментарии (16)


  1. KSCF
    18.07.2022 09:27
    -1

    Слайдер должен быть респонсив

    Собственно на этом у меня начался ступор )))

    Слайдер должен быть отзывчивым? Отзываться на фразу "к ноге"?


    1. yantishko Автор
      18.07.2022 09:28
      +1

      Как минимум отзываться на разных девайсах ????

      https://www.w3schools.com/html/html_responsive.asp


  1. non-aligned
    18.07.2022 12:32
    +1

    интересная статья. буквально месяц назад защищал ВКР бакалавра, создавал почти такой же слайдер с помощью разных инструментов (React, Vue, Angular). только еще работал с событиями для возможности свайпать слайды на сенсорных устройствах)


    1. yantishko Автор
      18.07.2022 21:30

      Точно, спасибо, хотел это добавить и забыл :)


    1. TAZAQ
      18.07.2022 23:22

      Сейчас на бакалавриате защищают слайдеры?)

      Или есть какая-то проблема с двойным дном?


      1. non-aligned
        19.07.2022 05:01

        я проводил сравнительный анализ фреймворков, а для практической части решил выбрать создание слайдера


    1. little-brother
      19.07.2022 00:06

      Если не секрет, то сколько по времени заняло? В 45 минут уложились на каждом фреймворке?


      1. yantishko Автор
        19.07.2022 00:32

        Первая пробная попытка заняла около 4х часов. На интервью решил за 45 минут, потому что уже знал структуру. Делал на React.js.

        Решение с 3мя слайдами для статьи заняло у меня 10 часов, а все потому, что я не мог понять, почему useEffect вызывается 2 раза и анимация срабатывает 2 раза, оказалось баг (либо фича) в реакте 18, откатился на 17-й и все стало ок.

        Без практики будет очень сложно


        1. Nik_o_lay
          19.07.2022 08:36
          +1

          это фича. достаточно было убрать strict mode

          https://reactjs.org/blog/2022/03/29/react-v18.html#new-strict-mode-behaviors


          1. yantishko Автор
            19.07.2022 08:36

            Убирал, не помогло :)


  1. Nik_o_lay
    19.07.2022 08:43

    const goTo = useCallback(goToSlide);

    какой профит использовать здесь useCallback?


    1. yantishko Автор
      19.07.2022 23:04

      согласен, в данном случае никакого, не дорефакторил. Обновил решение, спасибо


  1. wadowad
    20.07.2022 17:40

    Тоже потихоньку пилю свой слайдер (на jQuery). Кроме перечисленных у меня есть ещё два основных требования: возможность свайпа и "лёгкость" - допустимы только css-анимации. Для свайпа на мобильных использую сочетание overflow-x: auto и scroll-snap-type: x proximity. А что куда и на сколько сдвинулось считаю по факту, чем обеспечиваю совместимость с управлением "стрелками" и "точками". Разница между существующими решениями (например, в сравнении с тяжёлым Slick Slider) на мобильных устройствах заметна с первого прикосновения, т.к. css отрабатывает мгновенно.


    1. yantishko Автор
      20.07.2022 21:05

      Да, нужно использовать CSS по максимуму, он работает на GPU и это гораздо быстрее.

      Почему jQuery? Я думал он уже мертв :)


      1. wadowad
        20.07.2022 23:08

        Просто пишу на том, что уже знаю. Очень медленно осваиваю нативный js. Либо мной движет лень, либо я просто не успеваю. Многое хочется сделать, но времени в сутках не хватает. Программирование для меня скорее хобби. А менять род деятельности наверно уже поздновато. Вот как-то так...

        jQuery до ужаса прост, его синтаксис понятен "с пол-пинка", под него написано куча плагинов на все случаи жизни, поэтому он вряд ли умрёт. Статистика это подтверждает: https://github.com/get-set-fetch/scraper/blob/main/datasets/javascript-libs-from-top-1mm-sites/charts/most-used-js-libs-2022-06-05.svg


        1. yantishko Автор
          20.07.2022 23:44

          Я думаю это отличная возможность поработать с нативным js, изучать как работают эвенты разные