📜 ⬆️ ⬇️

Carousel on Vanilla.JS. Part 2

Good day. Today we will add the following features to our slider:


The first part is here . The markings of the carousel and its styles will remain the same. But JS rewrite.

Let's start by creating a renewable timer:

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(); } 

Now we will write the carousel constructor function, its private properties and methods:
')
 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; }; } 

The hts and htm methods are needed to handle touch events. Hts will be called when touchStart. Htm in event touchMove and, depending on the direction of the mov, call the method of the previous or next slide.

Now we will write public methods:

 // 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(); } }; 

Demo:


It's all! Less third-party lib => less traffic for the user => faster page load.

Source: https://habr.com/ru/post/327690/


All Articles