[Из песочницы] Карусель на Vanilla.JS

Прочитав эту статью решил запилить свою карусель с блэк-джеком и jQuery хотя нет, без него ибо 2017 год и он не особо и нужен. Создадим функцию, которая принимает объект с параметрами и делает слайдер. Некоторые моменты будут опущены, такие как: вендорные префиксы, таймер смены и т.д.
Первое что мы сделаем — разметка для карусели, на классах, а не id, дабы можно было использовать несколько раз один и тот же модуль на странице, ну и специфичность не была 3-его порядка.

HTML


У нас есть:
  • Блок — обертка для карусели, который скрывает все, что вылезает за его рамки;
  • Контейнер для самих слайдов, которые будут располагаться в строчку, с помощью flexbox, можем себе это позволить;
  • Блоки слайдов, которые скрывают все, что вылезает за их границы;
  • Блок — хелпер для выравнивания картинки по вертикали. И, внутри него уже будем располагать картинки.

В CSS используем БЭМ нотификацию, ибо не засоряем глобальную область. Сделаем его чуть-чуть адаптивным.
CSS
.b-carousel {
	width: 100%;
	overflow: hidden;
	position: relative;

	box-sizing: border-box;
	border: 1px solid;
}

	.b-carousel__prev,
	.b-carousel__next {
		position: absolute;
		top: 50%;
		left: 20px;
		width: 50px;
		height: 50px;
		background: #fff;
		transform: translateY(-50%) translateZ(0);
		cursor: pointer;
		text-indent: 100%;
		white-space: nowrap;
		overflow: hidden;
		z-index: 3;
	}

		.b-carousel__next {
			left: auto;
			right: 20px;
		}

	.b-carousel__wrap {
		display: flex;
		transition: transform .5s;
		will-change: transform;
		position: relative;
		z-index: 1;
		height: 100%;
	}

		.b-carousel__item {
			flex: 0 0 100%;
			overflow: hidden;
			display: flex;
			align-items: center;
			justify-content: center;
		}

			.b-carousel__img {
				width: 100%;
				display: block;
			}


Transform: translateZ (0) у контролов — хак для вынесения их на отдельный композитный слой, чтобы при смещении контейнера со слайдами не было перерисовки кнопок. А у обертки свойство will-change. Оно для броузера, чтобы он знал, что с блоком будут происходить какие-то действия.

Да начнем писать код. Создадим функцию, которая принимает объект с параметрами:

function Carousel(setting) {

	/* Scope privates methods and properties */
	let privates = {};

	/* Privates properties */
	privates.setting = setting;

	privates.sel = {
		"main": document.querySelector(privates.setting.main),
		"wrap": document.querySelector(privates.setting.wrap),
		"children": document.querySelector(privates.setting.wrap).children,
		"prev": document.querySelector(privates.setting.prev),
		"next": document.querySelector(privates.setting.next)
	};

	privates.opt = {
		"position": 0,
		"max_position": document.querySelector(privates.setting.wrap).children.length
	};

	// Control
	if(privates.sel.prev !== null) {
		privates.sel.prev.addEventListener('click', () => {
			this.prev_slide();
		});
	}

	if(privates.sel.next !== null) {
		privates.sel.next.addEventListener('click', () => {
			this.next_slide();
		});
	}

}

Методы для управления ей:
/* Public methods */
// Prev slide
this.prev_slide = () => {
	--privates.opt.position;

	if(privates.opt.position < 0) {
		privates.sel.wrap.classList.add('s-notransition');
		privates.opt.position = privates.opt.max_position - 1;
	}

	privates.sel.wrap.style["transform"] = `translateX(-${privates.opt.position}00%)`;
};


// Next slide
this.next_slide = () => {
	++privates.opt.position;

	if(privates.opt.position >= privates.opt.max_position) {
		privates.opt.position = 0;
	}

	privates.sel.wrap.style["transform"] = `translateX(-${privates.opt.position}00%)`;
};

Методы next_slide и prev_slide будут двигать обертку с помощью transform, дабы не было перерисовки блока, и анимация происходила на GPU.

Делаем карусель:

new Carousel({
	"main": ".js-carousel",
	"wrap": ".js-carousel__wrap",
	"prev": ".js-carousel__prev",
	"next": ".js-carousel__next"
});

Если нужна поддержка IE, то заменяем стрелочную функцию на:
Ну бросьте, все это знают
Если не все знают

Это все! Меньше кода — меньше трафика (jQuery 3.2 ~85kB). Контроль над параметрами и можем использовать несколько раз на странице.

Демо:

Если понравилась статья, то в скором времени будет продолжение с цикличной анимацией, touch-событиями и еще многими вкусными плюшками!

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

  • 24 апреля 2017 в 15:24

    0

    У подобных каруселей всегда хочется, чтобы при переключении с последнего на первый карусель не двигалась назад, а проходила вперёд.
    • 24 апреля 2017 в 15:24

      0

      Согласен, это будет в следующей статье =)

      • 24 апреля 2017 в 15:31

        0

        Здорово. Большой респект за отсутствие jQuery, кстати
        • 24 апреля 2017 в 15:41

          0

          Мне тоже нравится, не особо jQuery сегодня в зеленых броузерах нужен и в IE 8+

© Habrahabr.ru