Карусель на Vanilla.JS

от автора

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

HTML

<div class="wrap"> 	<div class="b-carousel js-carousel"> 		<buttom class="b-carousel__prev js-carousel__prev">Prev</buttom> 		<buttom class="b-carousel__next js-carousel__next">Next</buttom> 		<div class="b-carousel__wrap js-carousel__wrap"> 			<div class="b-carousel__item"> 				<img src="..." alt="" class="b-carousel__img"> 			</div> 			<div class="b-carousel__item"> 				<img src="..." alt="" class="b-carousel__img"> 			</div> 			<div class="b-carousel__item"> 				<img src="..." alt="" class="b-carousel__img"> 			</div> 			<div class="b-carousel__item"> 				<img src="..." alt="" class="b-carousel__img"> 			</div> 		</div> 	</div> </div> 

У нас есть:

  • Блок — обертка для карусели, который скрывает все, что вылезает за его рамки;
  • Контейнер для самих слайдов, которые будут располагаться в строчку, с помощью 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.1 ~34kB). Контроль над параметрами и можем использовать несколько раз на странице.

Демо:

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


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *