https://habrahabr.ru/post/327690/- Разработка веб-сайтов
- JavaScript
Доброго времени суток. Сегодня мы добавим следующие возможности в наш слайдер:
- Зацикленность карусели;
- Автоматическое переключение слайдов;
- Тач-события;
- События мыши.
Первая часть находиться
здесь. Разметка карусели и её стили оставим прежними. А вот JS перепишем.
Начнём с создания возобновляймого таймера:
function Timer(callback, delay) {
/* Private properties */
let timerId, start, remaining = delay;
/* Public methods */
this.resume = () => {
start = new Date();
timerId = setTimeout(() => {
remaining = delay;
this.resume();
callback();
}, remaining);
};
this.pause = () => {
clearTimeout(timerId);
remaining -= new Date() - start;
};
this.become = () => {
clearTimeout(timerId);
remaining = delay;
this.resume();
};
/* Constructor */
this.resume();
}
Теперь напишем функцию-конструктор карусели, её приватные свойства и методы:
function Carousel(setting) {
/* Scope private methods and properties */
let private = {},
xDown, yDown, xUp, yUp, xDiff, yDiff;
/* Private properties */
private.default = {
"touch": true,
"autoplay": false,
"autoplayDelay": 3000,
"pauseOnFocus": true,
"pauseOnHover": true
};
private.setting = Object.assign(private.default, setting);
private.isAnimationEnd = true;
private.sel = {
"wrap": document.querySelector(private.setting.wrap),
"children": document.querySelector(private.setting.wrap).children,
"prev": document.querySelector(private.setting.prev),
"next": document.querySelector(private.setting.next)
};
private.opt = {
"position": 0,
"max_position": document.querySelector(private.setting.wrap).children.length
};
/* Constructor */
// Clone first elem to end wrap
private.sel.wrap.appendChild(private.sel.children[0].cloneNode(true));
// Autoplay
if(private.setting.autoplay === true) {
private.timer = new Timer(this.next_slide, private.setting.autoplayDelay);
}
// Control
if(private.sel.prev !== null) {
private.sel.prev.addEventListener('click', () => {
this.prev_slide();
});
}
if(private.sel.next !== null) {
private.sel.next.addEventListener('click', () => {
this.next_slide();
});
}
// Touch events
if(private.setting.touch === true) {
private.sel.wrap.addEventListener('touchstart', private.hts, false);
private.sel.wrap.addEventListener('touchmove', private.htm, false);
}
// Pause on hover
if(private.setting.autoplay === true && private.setting.pauseOnHover === true) {
private.sel.wrap.addEventListener('mouseenter', () => {
private.timer.pause();
});
private.sel.wrap.addEventListener('mouseleave', () => {
private.timer.become();
});
}
private.hts = (e) => {
xDown = e.touches[0].clientX;
yDown = e.touches[0].clientY;
};
private.htm = (e) => {
if ( ! xDown || ! yDown ) {
return;
}
xUp = e.touches[0].clientX;
yUp = e.touches[0].clientY;
xDiff = xDown - xUp;
yDiff = yDown - yUp;
if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {
if ( xDiff > 0 ) {
this.next_slide();
} else {
this.prev_slide();
}
}
xDown = 0;
yDown = 0;
};
}
Методы hts и htm нужны для обработки тач-событий. Hts будет вызываться при touchStart. Htm при event touchMove и в зависимости от направления mov'а вызывать метод предыдущего или последующего слайда.
Теперь напишем публичные методы:
// Prev slide
this.prev_slide = () => {
if(!private.isAnimationEnd) {
return;
}
private.isAnimationEnd = false;
--private.opt.position;
if(private.opt.position < 0) {
private.sel.wrap.classList.add('s-notransition');
private.sel.wrap.style["transform"] = `translateX(-${private.opt.max_position}00%)`;
private.opt.position = private.opt.max_position - 1;
}
setTimeout(() => {
private.sel.wrap.classList.remove('s-notransition');
private.sel.wrap.style["transform"] = `translateX(-${private.opt.position}00%)`;
}, 10);
private.sel.wrap.addEventListener('transitionend', () => {
private.isAnimationEnd = true;
});
if(private.setting.autoplay === true) {
private.timer.become();
}
};
// Next slide
this.next_slide = () => {
if(!private.isAnimationEnd) {
return;
}
private.isAnimationEnd = false;
if(private.opt.position < private.opt.max_position) {
++private.opt.position;
}
private.sel.wrap.classList.remove('s-notransition');
private.sel.wrap.style["transform"] = `translateX(-${private.opt.position}00%)`;
private.sel.wrap.addEventListener('transitionend', () => {
if(private.opt.position >= private.opt.max_position) {
private.sel.wrap.style["transform"] = 'translateX(0)';
private.sel.wrap.classList.add('s-notransition');
private.opt.position = 0;
}
private.isAnimationEnd = true;
});
if(private.setting.autoplay === true) {
private.timer.become();
}
};
Демо:
Это все! Меньше сторонних либ => меньший трафик для пользователя => скорейшая загрузка страницы.