July 20th, 2021

JavaScript: карусель картинок, строим каркас 2

Начало: JavaScript: карусель картинок, строим каркас 1.

Продолжаю разбор задачи «Карусель» к подразделу 2.1 «Введение в браузерные события» второй части учебника по JavaScript.

У нас уже есть HTML-список из 10 тестовых картинок, настройку стилей которых я рассматривал в предыдущем посте.

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

Как создавать эту отдельную область просмотра, я уже примерно представлял, опираясь на стили футбольного поля из задач, разбиравшихся в предыдущих постах (например, тут). Саму эту отдельную область просмотра можно реализовать HTML-элементом div, в котором нашей областью просмотра станет клиентская часть HTML-элемента div (то есть его содержимое и внутренние отступы padding). Чтобы спрятать содержимое, выходящее за пределы нашей области просмотра (клиентской части HTML-элемента div), при создании футбольного поля использовалось указание overflow: hidden; в стиле футбольного поля. То же сделаем и мы. Меняем код:

Тело заданной HTML-страницы:
<div id="viewport">
  <ul>
    <li><img src="https://ru.js.cx/carousel/1.png"></li>
    <li><img src="https://ru.js.cx/carousel/2.png"></li>
    <li><img src="https://ru.js.cx/carousel/3.png"></li>
    <li><img src="https://ru.js.cx/carousel/4.png"></li>
    <li><img src="https://ru.js.cx/carousel/5.png"></li>
    <li><img src="https://ru.js.cx/carousel/6.png"></li>
    <li><img src="https://ru.js.cx/carousel/7.png"></li>
    <li><img src="https://ru.js.cx/carousel/8.png"></li>
    <li><img src="https://ru.js.cx/carousel/9.png"></li>
    <li><img src="https://ru.js.cx/carousel/10.png"></li>
  </ul>
</div>

К стилям добавляем стиль области просмотра карусели:
div#viewport {      /* стиль области просмотра карусели */
  overflow: hidden; /* скрыть картинки, выходящие за область просмотра */
}

Я решил писать скрипт, который будет отталкиваться от размера картинок, указанного в стиле картинок, хоть это и не требуется по условиям задачи. Мне хотелось, чтобы размер картинок в карусели можно было бы поменять в одном месте, в стиле картинок. Пишем код скрипта:
// размер картинок (все картинки — равные друг другу квадраты)
const PIC_SIZE = document.querySelector("ul img").offsetWidth;
// размер области просмотра карусели картинок
const VIEWPORT_SIZE = 3 * PIC_SIZE;

// предварительная настройка каркаса карусели
viewport.style.width = VIEWPORT_SIZE + "px";

Как видно из этого кода, область просмотра карусели вмещает три картинки из заданных десяти (остальные пока скрыты, так как выходят за область просмотра карусели).

Сначала я думал, что для построения карусели мне хватит одного HTML-элемента div. Но потом я стал прикидывать, куда здесь вставить кнопки прокрутки карусели (их две: влево и вправо), и понял, что, по идее, нужен еще один HTML-элемент div (собственно, сама карусель), который будет содержать две кнопки и область просмотра карусели. Меняем код:

Меняем тело заданной HTML-страницы:
<div id="carusel">
  <div id="viewport">
    <ul>
      <li><img src="https://ru.js.cx/carousel/1.png"></li>
      <li><img src="https://ru.js.cx/carousel/2.png"></li>
      <li><img src="https://ru.js.cx/carousel/3.png"></li>
      <li><img src="https://ru.js.cx/carousel/4.png"></li>
      <li><img src="https://ru.js.cx/carousel/5.png"></li>
      <li><img src="https://ru.js.cx/carousel/6.png"></li>
      <li><img src="https://ru.js.cx/carousel/7.png"></li>
      <li><img src="https://ru.js.cx/carousel/8.png"></li>
      <li><img src="https://ru.js.cx/carousel/9.png"></li>
      <li><img src="https://ru.js.cx/carousel/10.png"></li>
    </ul>
  </div>
</div>

Меняем стиль области просмотра карусели, добавим внешние отступы. Сверху и снизу — для красоты, слева и справа — чтобы выделить место под кнопки:
div#carusel {         /* стиль карусели */
  border: 1px solid gray;    /* от границы отсчитываются отступы области просмотра */
}

div#viewport {        /* стиль области просмотра карусели */
  margin: 10px 50px;         /* 50px — слева и справа, место для кнопок */
  overflow: hidden;          /* скрыть картинки, выходящие за область просмотра */
  background-color: #f0f0f0; /* фон области просмотра */
}

Добавляем настройку ширины карусели в скрипт:
// размер картинок (все картинки — равные друг другу квадраты)
const PIC_SIZE = document.querySelector("ul img").offsetWidth;
// размер области просмотра карусели картинок
const VIEWPORT_SIZE = 3 * PIC_SIZE;

// предварительная настройка каркаса карусели
viewport.style.width = VIEWPORT_SIZE + "px";
carusel.style.width = 50 + VIEWPORT_SIZE + 50 + "px";

Вот что получилось в моём браузере «Microsoft Edge» на движке «Chromium» (картинка):



Тонкая серая линия слева и сверху — это граница области просмотра браузера. На этой иллюстрации видна область просмотра карусели (у нее серый фон), в которой видны первые три картинки из десяти заданных (остальные семь скрыты, потому что выходят за правую границу области просмотра карусели). Также видна темно-серая граница самой карусели. Между границей карусели и границей области просмотра слева и справа виден промежуток в 50px, предназначенный для кнопок карусели.

Переходим к созданию кнопок. Вставим их код (он уже был дан изначально в коде заданной HTML-страницы) в тело HTML-страницы в содержимое карусели перед областью просмотра карусели:
<div id="carusel">
  <button class="arrow">&#8678;</button> <!-- кнопка «влево» -->
  <button class="arrow">&#8680;</button> <!-- кнопка «вправо» -->
  <div id="viewport">
    <ul>
      <li><img src="https://ru.js.cx/carousel/1.png"></li>
      <li><img src="https://ru.js.cx/carousel/2.png"></li>
      <li><img src="https://ru.js.cx/carousel/3.png"></li>
      <li><img src="https://ru.js.cx/carousel/4.png"></li>
      <li><img src="https://ru.js.cx/carousel/5.png"></li>
      <li><img src="https://ru.js.cx/carousel/6.png"></li>
      <li><img src="https://ru.js.cx/carousel/7.png"></li>
      <li><img src="https://ru.js.cx/carousel/8.png"></li>
      <li><img src="https://ru.js.cx/carousel/9.png"></li>
      <li><img src="https://ru.js.cx/carousel/10.png"></li>
    </ul>
  </div>
</div>
Символы стрелок я заменил их кодами в Юникоде. Это было необязательно, но мне так больше нравится: сразу понятно, о каком именно символе идет речь.

К тому же, в моем текстовом редакторе «Notepad++» по умолчанию используется шрифт «Courier New», в котором нет таких символов-стрелок, поэтому вместо них отражаются квадратики (замещающие символы на случай, когда определенных символов в шрифте нет). При этом в браузере эти символы-стрелки успешно отображаются (я ранее писал, почему: браузер может подобрать и отобразить требуемые символы из других шрифтов, если в текущем шрифте их нет).

Вставленные в карусель кнопки нужно правильно разместить (позиционировать). В стилях включим для них абсолютное позиционирование (указание position: absolute; в стиле кнопок) относительно родительского HTML-элемента (указание position: relative; в стиле карусели):
.arrow {              /* стиль кнопок */
  position: absolute;        /* абсолютное позиционирование относительно карусели */
}

div#carusel {         /* стиль карусели */
  border: 1px solid gray;    /* от границы отсчитываются отступы области просмотра */
  position: relative;        /* для позиционирования кнопок */
}

div#viewport {        /* стиль области просмотра карусели */
  margin: 10px 50px;         /* 50px — слева и справа, место для кнопок */
  overflow: hidden;          /* скрыть картинки, выходящие за область просмотра */
  background-color: #f0f0f0; /* фон области просмотра */
}

Сами координаты вычислим в скрипте. Дополняем код:
// размер картинок (все картинки — равные друг другу квадраты)
const PIC_SIZE = document.querySelector("ul img").offsetWidth;
// размер области просмотра карусели картинок
const VIEWPORT_SIZE = 3 * PIC_SIZE;

// настройка ширины карусели и области просмотра карусели
viewport.style.width = VIEWPORT_SIZE + "px";
carusel.style.width = 50 + VIEWPORT_SIZE + 50 + "px";

// позиционируем кнопки
let arrowLeft  = document.querySelectorAll(".arrow")[0],
    arrowRight = document.querySelectorAll(".arrow")[1];
arrowLeft.style.left = "10px";
arrowLeft.style.top = (10 + PIC_SIZE + 10) / 2 - arrowLeft.offsetHeight / 2 + "px";
arrowRight.style.right = "10px";
arrowRight.style.top = (10 + PIC_SIZE + 10) / 2 - arrowRight.offsetHeight / 2 + "px";
По горизонтали кнопки располагаются на расстоянии 10px от границы карусели. По вертикали координата вычисляется так, чтобы кнопка оказалась на половине высоты карусели. При этом высоту, как мы помним из предыдущих задач, нужно скорректировать на высоту самой кнопки, потому что мы указываем координаты левого (и правого для другой кнопки) верхнего угла кнопки, а не ее центра.

Вот что получилось в моем браузере (картинка):



На этом построение каркаса карусели закончим и перейдем к написанию ее функционала. Я в своем решении в итоге настроил стили так, что карусель получилась в точности такая же, как и в действующем примере от авторов задачи, который можно рассмотреть на странице задачи. Но, в принципе, дальше уже идет настройка цветов HTML-элементов и их частей, закругления углов HTML-элементов (с помощью указания, к примеру, border-radius: 15px;) и тому подобное, что не слишком важно для изучения текущего подраздела обсуждаемого учебника.

Продолжение тут.