📜 ⬆️ ⬇️

Introduction to developing a slideshow in JavaScript

In this article we describe the basic principles of building a slideshow on JavaScript, what they are built from (HTML, CSS, JavaScript) and the techniques that are used to create them.

JS-code will be presented in two forms - vanilla and jQuery. This is done specifically to emphasize: in modern browsers, even simple JS can be perfectly used, especially by combining it with animations and CSS transitions. jQuery is good if we don’t want to worry about browser incompatibilities or use a simpler API. The code provided is for demonstration purposes only.

In the examples with vanilla JS, I use the simplest method of initializing objects, init (). This method calls the necessary code to create an object instance via new. In this thread on Stack Overflow, everything is explained in more detail. Why objects, and not functions? To answer this question, you would need a separate article - but, in general, just to make the code more organized and easy to reuse.

HTML structure


HTML markup should be such that the page remains readable and without CSS and JS. Therefore, you need to figure out what components will make up our structure. Usually this:
')
1) the outermost container
2) internal wrapper
3) multiple slide elements
4) Wrapper for links to pages
5) two buttons "previous" and "next"

Components 2, 4 and 5 are optional because:

- slides can be wrapped in one element. This is done when the transition between slides is done through fade in / fade out.
- links to pages and buttons can be omitted if the slide show is automatic, and occurs without user intervention

An example of a possible HTML structure:

<div class="slider" id="main-slider"><!--    --> <div class="slider-wrapper"><!--   --> <div class="slide">...</div><!-- slides --> <div class="slide">...</div> <div class="slide">...</div> </div> <div class="slider-nav"><!--  ""  "" --> <button type="button" class="slider-previous"></button> <button type="button" class="slider-next"></button> </div> </div> 


For slides, it is better to use classes, since there can be several slide shows on one page. To identify different slide shows, you can use the ID in the external container.

Elements with buttons are used instead of links, because the links here are not suitable, and we will work with buttons from a script (for details, read the article You can't create a button ).

If the slides contain only pictures, you can slightly change the structure:

 <div class="slider" id="main-slider"><!--    --> <div class="slider-wrapper"><!--   --> <img src="image1.jpg" alt="First" class="slide" /><!-- slides --> <img src="image2.jpg" alt="Second" class="slide" /> <img src="image3.jpg" alt="Third" class="slide" /> </div> <div class="slider-nav"><!--  ""  "" --> <button type="button" class="slider-previous"></button> <button type="button" class="slider-next"></button> </div> </div> 


Remember to add a meaningful value to the alt attribute.

To use links to pages you can do the following:

 <div class="slider" id="main-slider"><!--    --> <div class="slider-wrapper"><!--   --> <div class="slide" id="slide-1">...</div><!-- slides --> <div class="slide" id="slide-2">...</div> <div class="slide" id="slide-3">...</div> </div> <div class="slider-nav"><!—   --> <a href="#slide-1">1</a> <a href="#slide-2">2</a> <a href="#slide-3">3</a> </div> </div> 


Now each link leads to its slide thanks to the anchor. This is specifically made so that the page works without JS.

There are slide shows, combining links and management:

 <div class="slider" id="main-slider"><!--    --> <div class="slider-wrapper"><!--   --> <!-- slides --> <div class="slide" id="slide-1" data-image="image1.jpg"></div> <div class="slide" id="slide-2" data-image="image2.jpg"></div> <div class="slide" id="slide-3" data-image="image3.jpg"></div> </div> <!--  ""  "" --> <div class="slider-nav"> <button type="button" class="slider-previous"></button> <button type="button" class="slider-next"></button> </div> <!--    --> <div class="slider-pagination"> <a href="#slide-1">1</a> <a href="#slide-2">2</a> <a href="#slide-3">3</a> </div> </div> 


Note the use of the “data” attributes — some slideshows can insert pictures as background, and these attributes will be used in the script as places for the background and slide connection.

Using Lists

Semantically, the right approach would be to use list items as slides. In this case, the structure will be as follows:

 <ul class="slider-wrapper"><!--   --> <li class="slide" id="slide-1">...</li><!--  --> <li class="slide" id="slide-2">...</li> <li class="slide" id="slide-3">...</li> </ul> 


If the slide order is well defined (for example, in a presentation), you can use numbered lists.
 

CSS
:

<div class="slider" id="main-slider"><!-- --> <div class="slider-wrapper"><!-- --> <img src="image1.jpg" alt="First" class="slide" /><!-- slides --> <img src="image2.jpg" alt="Second" class="slide" /> <img src="image3.jpg" alt="Third" class="slide" /> </div> <div class="slider-nav"><!-- "" "" --> <button type="button" class="slider-previous"></button> <button type="button" class="slider-next"></button> </div> </div>



CSS
:

<div class="slider" id="main-slider"><!-- --> <div class="slider-wrapper"><!-- --> <img src="image1.jpg" alt="First" class="slide" /><!-- slides --> <img src="image2.jpg" alt="Second" class="slide" /> <img src="image3.jpg" alt="Third" class="slide" /> </div> <div class="slider-nav"><!-- "" "" --> <button type="button" class="slider-previous"></button> <button type="button" class="slider-next"></button> </div> </div>



CSS
:

<div class="slider" id="main-slider"><!-- --> <div class="slider-wrapper"><!-- --> <img src="image1.jpg" alt="First" class="slide" /><!-- slides --> <img src="image2.jpg" alt="Second" class="slide" /> <img src="image3.jpg" alt="Third" class="slide" /> </div> <div class="slider-nav"><!-- "" "" --> <button type="button" class="slider-previous"></button> <button type="button" class="slider-next"></button> </div> </div>


Since the slideshow will go from right to left, then the outer container will have a fixed size, and the inner one will be wider since it contains all the slides. The first slide will be visible. This is set via overflow:

 .slider { width: 1024px; overflow: hidden; } .slider-wrapper { width: 9999px; height: 683px; position: relative; transition: left 500ms linear; } 


Inner wrapper styles include:

- large width
- fixed height, maximum slide height
- position: relative, which allows you to create a moving slide
- CSS transition left, which will make the movement smooth. For simplicity, we did not specify all the prefixes. You can also use CSS transformations for this (along with translation).

Slides have a float attribute so that they line up in a single line. They are positioned relatively so that you can get their offset to the left in JS. We use it to create a slip effect.

 .slide { float: left; position: relative; width: 1024px; height: 683px; } 


Although we set a certain width, in the script we can change it by multiplying the number of slides by the width of the slide. You never know what width might be needed.

Navigation is done through the “Previous” and “Next” buttons. Zero out their default styles and assign our own:

 .slider-nav { height: 40px; width: 100%; margin-top: 1.5em; } .slider-nav button { border: none; display: block; width: 40px; height: 40px; cursor: pointer; text-indent: -9999em; background-color: transparent; background-repeat: no-repeat; } .slider-nav button.slider-previous { float: left; background-image: url(previous.png); } .slider-nav button.slider-next { float: right; background-image: url(next.png); } 


When using links to pages instead of buttons, you can make the following styles:

 .slider-nav { text-align: center; margin-top: 1.5em; } .slider-nav a { display: inline-block; text-decoration: none; border: 1px solid #ddd; color: #444; width: 2em; height: 2em; line-height: 2; text-align: center; } .slider-nav a.current { border-color: #000; color: #000; font-weight: bold; } 


These classes will be assigned from the script dynamically.

This approach is suitable for the slip effect. If we want to achieve the effect of disappearing and appearing, we need to change the styles, since the float adds horizontal indents between the slides. That is, we don’t need slides on one line - we need a bundle of slides:

 .slider { width: 1024px; margin: 2em auto; } .slider-wrapper { width: 100%; height: 683px; position: relative; /*      */ } .slide { position: absolute; /*     */ width: 100%; height: 100%; opacity: 0; /*    */ transition: opacity 500ms linear; } /*     */ .slider-wrapper > .slide:first-child { opacity: 1; } 

To hide slides, we use the opacity property, because programs for reading data from the screen skip the contents of elements that have display: none set (see CSS in Action: Invisible Content Just for Screen Reader Users ).

Thanks to the contextual positioning of CSS, we created a “stack” of slides, where the last slide in the source is ahead of the others. But we do not need it. To preserve the order of the slides, we need to hide all the slides, except the first.

JS uses the CSS transition by changing the value of the opacity property of the current slide, and zeroing this value for all others.

IE9 issues

IE9 does not support CSS transitions . Changing the value of a property instantly changes its appearance. For smoothness, we have to use jQuery. Details on possible solutions read in this thread on Stack Overflow.

Javascript code


Slideshow without pagination

Slideshows without pagination work by pressing the “Next” and “Previous” buttons. They can be considered as increment and decrement operators. There is always a pointer (or cursor) that will be increased or decreased each time you press a button. Its initial value is 0, and the goal is to select the current slide in the same way as the elements of the array are selected.

Therefore, when we click Next for the first time, the pointer increases by 1 and we get the second slide. Clicking on the Previous, we reduce the pointer and get the first slide. Etc.

Together with the pointer, we use the jQuery .eq () method to get the current slide. On pure JS, it looks like this:

 function Slideshow( element ) { this.el = document.querySelector( element ); this.init(); } Slideshow.prototype = { init: function() { this.slides = this.el.querySelectorAll( ".slide" ); //... }, _slideTo: function( pointer ) { var currentSlide = this.slides[pointer]; //... } }; 


Remember - NodeList uses indexes just like an array. Another way to select the current slide CSS3 selectors:

 Slideshow.prototype = { init: function() { //... }, _slideTo: function( pointer ) { var n = pointer + 1; var currentSlide = this.el.querySelector( ".slide:nth-child(" + n + ")" ); //... } }; 


The CSS3 selector: nth-child () counts elements from 1, so you need to add one to the pointer. After selecting a slide, its parent container must be shifted from right to left. In jQuery, you can use the .animate () method:

 (function( $ ) { $.fn.slideshow = function( options ) { options = $.extend({ wrapper: ".slider-wrapper", slides: ".slide", //... speed: 500, easing: "linear" }, options); var slideTo = function( slide, element ) { var $currentSlide = $( options.slides, element ).eq( slide ); $( options.wrapper, element ). animate({ left: - $currentSlide.position().left }, options.speed, options.easing ); }; //... }; })( jQuery ); 


In normal JS there is no .animate () method, so we use CSS transitions:

 .slider-wrapper { position: relative; //  transition: left 500ms linear; } 


Now you can change the left property dynamically through the style object:

 function Slideshow( element ) { this.el = document.querySelector( element ); this.init(); } Slideshow.prototype = { init: function() { this.wrapper = this.el.querySelector( ".slider-wrapper" ); this.slides = this.el.querySelectorAll( ".slide" ); //... }, _slideTo: function( pointer ) { var currentSlide = this.slides[pointer]; this.wrapper.style.left = "-" + currentSlide.offsetLeft + "px"; } }; 


Now we need to make a click event for each control. In jQuery, you can take the .on () method, and in pure JS, the addEventListener () method.

You also need to check whether the pointer has reached the list boundaries - 0 for “Previous” and total number of slides for “Next”. In each case, you must hide the corresponding button:

 (function( $ ) { $.fn.slideshow = function( options ) { options = $.extend({ wrapper: ".slider-wrapper", slides: ".slide", previous: ".slider-previous", next: ".slider-next", //... speed: 500, easing: "linear" }, options); var slideTo = function( slide, element ) { var $currentSlide = $( options.slides, element ).eq( slide ); $( options.wrapper, element ). animate({ left: - $currentSlide.position().left }, options.speed, options.easing ); }; return this.each(function() { var $element = $( this ), $previous = $( options.previous, $element ), $next = $( options.next, $element ), index = 0, total = $( options.slides ).length; $next.on( "click", function() { index++; $previous.show(); if( index == total - 1 ) { index = total - 1; $next.hide(); } slideTo( index, $element ); }); $previous.on( "click", function() { index--; $next.show(); if( index == 0 ) { index = 0; $previous.hide(); } slideTo( index, $element ); }); }); }; })( jQuery ); 


And on pure JS it looks like this:

 function Slideshow( element ) { this.el = document.querySelector( element ); this.init(); } Slideshow.prototype = { init: function() { this.wrapper = this.el.querySelector( ".slider-wrapper" ); this.slides = this.el.querySelectorAll( ".slide" ); this.previous = this.el.querySelector( ".slider-previous" ); this.next = this.el.querySelector( ".slider-next" ); this.index = 0; this.total = this.slides.length; this.actions(); }, _slideTo: function( pointer ) { var currentSlide = this.slides[pointer]; this.wrapper.style.left = "-" + currentSlide.offsetLeft + "px"; }, actions: function() { var self = this; self.next.addEventListener( "click", function() { self.index++; self.previous.style.display = "block"; if( self.index == self.total - 1 ) { self.index = self.total - 1; self.next.style.display = "none"; } self._slideTo( self.index ); }, false); self.previous.addEventListener( "click", function() { self.index--; self.next.style.display = "block"; if( self.index == 0 ) { self.index = 0; self.previous.style.display = "none"; } self._slideTo( self.index ); }, false); } }; 


Examples

jQuery: slideshow
Pure javascript slideshow

Pagination slideshow

In such a slide show, each link is responsible for one slide, so the pointer is not needed. Animations do not change - changing the way the user moves through the slides. For jQuery we will have the following code:

 (function( $ ) { $.fn.slideshow = function( options ) { options = $.extend({ wrapper: ".slider-wrapper", slides: ".slide", nav: ".slider-nav", speed: 500, easing: "linear" }, options); var slideTo = function( slide, element ) { var $currentSlide = $( options.slides, element ).eq( slide ); $( options.wrapper, element ). animate({ left: - $currentSlide.position().left }, options.speed, options.easing ); }; return this.each(function() { var $element = $( this ), $navigationLinks = $( "a", options.nav ); $navigationLinks.on( "click", function( e ) { e.preventDefault(); var $a = $( this ), $slide = $( $a.attr( "href" ) ); slideTo( $slide, $element ); $a.addClass( "current" ).siblings(). removeClass( "current" ); }); }); }; })( jQuery ); 


In this case, each anchor corresponds to the ID of a particular slide. In pure JS, you can use both it and the data attribute, which stores the numeric index of the slides inside the NodeList:

 function Slider( element ) { this.el = document.querySelector( element ); this.init(); } Slider.prototype = { init: function() { this.links = this.el.querySelectorAll( "#slider-nav a" ); this.wrapper = this.el.querySelector( "#slider-wrapper" ); this.navigate(); }, navigate: function() { for ( var i = 0; i < this.links.length; ++i ) { var link = this.links[i]; this.slide( link ); } }, slide: function( element ) { var self = this; element.addEventListener( "click", function( e ) { e.preventDefault(); var a = this; self.setCurrentLink( a ); var index = parseInt( a.getAttribute( "data-slide" ), 10 ) + 1; var currentSlide = self.el.querySelector( ".slide:nth-child(" + index + ")" ); self.wrapper.style.left = "-" + currentSlide.offsetLeft + "px"; }, false); }, setCurrentLink: function(link) { var parent = link.parentNode; var a = parent.querySelectorAll( "a" ); link.className = "current"; for ( var j = 0; j < a.length; ++j ) { var cur = a[j]; if ( cur !== link ) { cur.className = ""; } } } }; 


Starting with IE10, you can manage classes through classList:

 link.classList.add( "current" ); 


And with IE11, data attributes can be obtained through the dataset property:

 var index = parseInt( a.dataset.slide, 10 ) + 1; 


Examples

jQuery: pagination slideshow
Javascript: pagination slideshow

Slideshow with pagination and controls

Such slide shows present some complexity for the code — you have to combine the use of the pointer and page hashes. That is, the current slide must be selected both on the basis of the position of the pointer, and on the basis of the slide selected through links.

If we click on the link number 3, then the pointer must be set to 2 - so that by clicking on the "Previous", we hit the second slide. That is, you need to do synchronization.

This can be synchronized through the index number of each link in the DOM. One link - one slide, so their indices will be 0, 1, 2, etc.

On jQuery, the code will be like this:

 (function( $ ) { $.fn.slideshow = function( options ) { options = $.extend({ //... pagination: ".slider-pagination", //... }, options); $.fn.slideshow.index = 0; return this.each(function() { var $element = $( this ), //... $pagination = $( options.pagination, $element ), $paginationLinks = $( "a", $pagination ), //... $paginationLinks.on( "click", function( e ) { e.preventDefault(); var $a = $( this ), elemIndex = $a.index(); // DOM numerical index $.fn.slideshow.index = elemIndex; if( $.fn.slideshow.index > 0 ) { $previous.show(); } else { $previous.hide(); } if( $.fn.slideshow.index == total - 1 ) { $.fn.slideshow.index = total - 1; $next.hide(); } else { $next.show(); } slideTo( $.fn.slideshow.index, $element ); $a.addClass( "current" ). siblings().removeClass( "current" ); }); }); }; //... })( jQuery ); 


It is immediately obvious that the visibility of the cursor has changed - now the index is declared as a property of the slideshow object. Thus, we avoid scope problems that can be created by callbacks in jQuery. Now the cursor is available everywhere, and even outside the namespace of the plugin, since it is declared as a public property of the slideshow object.

The .index () method gives the numeric index of each link.

There is no such method in pure JS, so it’s easier to use data attributes:

 (function() { function Slideshow( element ) { this.el = document.querySelector( element ); this.init(); } Slideshow.prototype = { init: function() { this.wrapper = this.el.querySelector( ".slider-wrapper" ); this.slides = this.el.querySelectorAll( ".slide" ); this.previous = this.el.querySelector( ".slider-previous" ); this.next = this.el.querySelector( ".slider-next" ); this.navigationLinks = this.el.querySelectorAll( ".slider-pagination a" ); this.index = 0; this.total = this.slides.length; this.setup(); this.actions(); }, //... setup: function() { var self = this; //... for( var k = 0; k < self.navigationLinks.length; ++k ) { var pagLink = self.navigationLinks[k]; pagLink.setAttribute( "data-index", k ); //  pagLink.dataset.index = k; } }, //... }; })(); 


Now we can connect our procedures with links and use the newly created data attributes:

 actions: function() { var self = this; //... for( var i = 0; i < self.navigationLinks.length; ++i ) { var a = self.navigationLinks[i]; a.addEventListener( "click", function( e ) { e.preventDefault(); var n = parseInt( this.getAttribute( "data-index" ), 10 ); //  var n = parseInt( this.dataset.index, 10 ); self.index = n; if( self.index == 0 ) { self.index = 0; self.previous.style.display = "none"; } if( self.index > 0 ) { self.previous.style.display = "block"; } if( self.index == self.total - 1 ) { self.index = self.total - 1; self.next.style.display = "none"; } else { self.next.style.display = "block"; } self._slideTo( self.index ); self._highlightCurrentLink( this ); }, false); } } 


Examples

jQuery: pagination slideshow and controls
Javascript: pagination slideshow and controls

Understand the size

Let's go back to the following CSS rule:

 .slider-wrapper { width: 9999px; height: 683px; position: relative; transition: left 500ms linear; } 


If we have a lot of slides, then 9999 may not be enough. It is necessary to adjust the dimensions for the slides on the basis of the width of each of them and their number.

On jQuery, it's simple:

 // -    return this.each(function() { var $element = $( this ), total = $( options.slides ).length; //... $( options.slides, $element ).width( $( window ).width() ); $( options.wrapper, $element ).width( $( window ).width() * total ); //... }); 


Take the width of the window and set the width of each slide. The total width of the internal wrapper is obtained by multiplying the width of the window and the number of slides.

 // -   return this.each(function() { var $element = $( this ), total = $( options.slides ).length; //... $( options.wrapper, $element ).width( $( options.slides ).eq( 0 ).width() * total ); //... }); 


Here the initial width is given by the width of each slide. You only need to set the overall width of the wrapper.

Now the inner container is quite wide. On pure JS, this is done in much the same way:

 // -    Slideshow.prototype = { init: function() { this.wrapper = this.el.querySelector( ".slider-wrapper" ); this.slides = this.el.querySelectorAll( ".slide" ); //... this.total = this.slides.length; this.setDimensions(); this.actions(); }, setDimensions: function() { var self = this; // Viewport's width var winWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; var wrapperWidth = winWidth * self.total; for( var i = 0; i < self.total; ++i ) { var slide = self.slides[i]; slide.style.width = winWidth + "px"; } self.wrapper.style.width = wrapperWidth + "px"; }, //... }; // -   Slideshow.prototype = { init: function() { this.wrapper = this.el.querySelector( ".slider-wrapper" ); this.slides = this.el.querySelectorAll( ".slide" ); //... this.total = this.slides.length; this.setDimensions(); this.actions(); }, setDimensions: function() { var self = this; var slideWidth = self.slides[0].offsetWidth; // Single slide's width var wrapperWidth = slideWidth * self.total; self.wrapper.style.width = wrapperWidth + "px"; }, //... }; 


Fading effects

Fade effects are often used in slideshows. The current slide disappears and the next one appears. JQuery has fadeIn () and fadeOut () methods that work with both the opacity property and the display, so the element is removed from the page upon completion of the animation (display: none).

In pure JS, it's best to work with the opacity property and use the CSS positioning stack. Then initially the slide will be visible (opacity: 1), while others are hidden (opacity: 0).

The following style set demonstrates this method:

 .slider { width: 100%; overflow: hidden; position: relative; height: 400px; } .slider-wrapper { width: 100%; height: 100%; position: relative; } .slide { position: absolute; width: 100%; height: 100%; opacity: 0; } .slider-wrapper > .slide:first-child { opacity: 1; } 


In pure JS, you must register the CSS transition of each slide:

 .slide { float: left; position: absolute; width: 100%; height: 100%; opacity: 0; transition: opacity 500ms linear; } 


With jQuery, to use the fadeIn () and fadeOut () methods, you need to change the opacity and display:

 .slide { float: left; position: absolute; width: 100%; height: 100%; display: none; } .slider-wrapper > .slide:first-child { display: block; } 


The jQuery code is as follows:

 (function( $ ) { $.fn.slideshow = function( options ) { options = $.extend({ wrapper: ".slider-wrapper", previous: ".slider-previous", next: ".slider-next", slides: ".slide", nav: ".slider-nav", speed: 500, easing: "linear" }, options); var slideTo = function( slide, element ) { var $currentSlide = $( options.slides, element ).eq( slide ); $currentSlide. animate({ opacity: 1 }, options.speed, options.easing ). siblings( options.slides ). css( "opacity", 0 ); }; //... }; })( jQuery ); 


When animating opacity, you also need to change the values ​​of this property for the remaining slides.

In javascript it will be:

 Slideshow.prototype = { //... _slideTo: function( slide ) { var currentSlide = this.slides[slide]; currentSlide.style.opacity = 1; for( var i = 0; i < this.slides.length; i++ ) { var slide = this.slides[i]; if( slide !== currentSlide ) { slide.style.opacity = 0; } } }, //... }; 


Examples

jQuery: fade slideshow
Javascript: fade slideshow

Media elements: video

We can include a video in a slideshow. Here is an example of a video slideshow from Vimeo:

 <div class="slider-wrapper"><!—  --> <div class="slide"> <iframe src="https://player.vimeo.com/video/109608341?title=0&byline=0&portrait=0" width="1024" height="626" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div><!-- slides --> <div class="slide"> <iframe src="https://player.vimeo.com/video/102570343?title=0&byline=0&portrait=0" width="1024" height="576" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> <div class="slide"> <iframe src="https://player.vimeo.com/video/97620325?title=0&byline=0&portrait=0" width="1024" height="576" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> </div> 


Videos are included via iframe. This is the same inline-block replaceable as the picture. Replaced - because the content is taken from an external source.

To create a full-page slide show, you need to change the styles as follows:

 html, body { margin: 0; padding: 0; height: 100%; min-height: 100%; /*       */ } .slider { width: 100%; overflow: hidden; height: 100%; min-height: 100%; /*      */ position: absolute; /*   */ } .slider-wrapper { width: 100%; height: 100%; /*      */ position: relative; } .slide { float: left; position: absolute; width: 100%; height: 100%; } .slide iframe { display: block; /*   */ position: absolute; /*   */ width: 100%; height: 100%; /*      */ } 


Examples

jQuery: full page video slideshow
Javascript: full page video slideshow

Automatic Slideshows

Automatic slide shows use timers. Each time the callback function is called setInterval (), the cursor will increase by 1 and the next slide will be selected in this way.

When the cursor reaches the maximum number of slides, it should be zeroed.

Endless slide shows quickly annoy users. It is best to stop the animation when the user hovers over it with the mouse, and restore when the cursor leaves.

On jQuery:

 (function( $ ) { $.fn.slideshow = function( options ) { options = $.extend({ slides: ".slide", speed: 3000, easing: "linear" }, options); var timer = null; //  var index = 0; //  var slideTo = function( slide, element ) { var $currentSlide = $( options.slides, element ).eq( slide ); $currentSlide.stop( true, true ). animate({ opacity: 1 }, options.speed, options.easing ). siblings( options.slides ). css( "opacity", 0 ); }; var autoSlide = function( element ) { //   timer = setInterval(function() { index++; //    1 if( index == $( options.slides, element ).length ) { index = 0; //   } slideTo( index, element ); }, options.speed); //   ,     .animate() }; var startStop = function( element ) { element.hover(function() { //   clearInterval( timer ); timer = null; }, function() { autoSlide( element ); //   }); }; return this.each(function() { var $element = $( this ); autoSlide( $element ); startStop( $element ); }); }; })( jQuery ); 


Both parameters of the .stop () method are set to true, since we don't need to create an animation queue from our sequence.

On pure JS the code becomes easier. We register the CSS transition for each slide with a certain duration:

 .slide { transition: opacity 3s linear; /* 3  = 3000  */ } 


And the code will be as follows:

 (function() { function Slideshow( element ) { this.el = document.querySelector( element ); this.init(); } Slideshow.prototype = { init: function() { this.slides = this.el.querySelectorAll( ".slide" ); this.index = 0; //  this.timer = null; //  this.action(); this.stopStart(); }, _slideTo: function( slide ) { var currentSlide = this.slides[slide]; currentSlide.style.opacity = 1; for( var i = 0; i < this.slides.length; i++ ) { var slide = this.slides[i]; if( slide !== currentSlide ) { slide.style.opacity = 0; } } }, action: function() { var self = this; // Initializes the sequence self.timer = setInterval(function() { self.index++; //    1 if( self.index == self.slides.length ) { self.index = 0; //   } self._slideTo( self.index ); }, 3000); //   ,     CSS }, stopStart: function() { var self = this; //   self.el.addEventListener( "mouseover", function() { clearInterval( self.timer ); self.timer = null; }, false); //   self.el.addEventListener( "mouseout", function() { self.action(); }, false); } }; })(); 


Examples

jQuery: automatic slideshow
JavaScript: automatic slideshow

Keyboard navigation

- , .. . .

keyCode event. ( ).

, "" "", "" "". jQuery :

 $( "body" ).on( "keydown", function( e ) { var code = e.keyCode; if( code == 39 ) { //   $next.trigger( "click" ); } if( code == 37 ) { //   $previous.trigger( "click" ); } }); 


JS .trigger() dispatchEvent():

 document.body.addEventListener( "keydown", function( e ) { var code = e.keyCode; var evt = new MouseEvent( "click" ); //   if( code == 39 ) { //   self.next.dispatchEvent( evt ); } if( code == 37 ) { //   self.previous.dispatchEvent( evt ); } }, false); 


. , , , . , DOM, .

Examples

jQuery: -
JavaScript: -


It would be nice to be able to attach some code to any slide show action that would be executed when this action is performed. This is the purpose of the callback functions — they are executed only when a specific action occurs. Suppose our slide show has signatures and they are hidden by default. At the time of the animation, we need to show the caption for the current slide or even something to do with it.

In jQuery, you can create a callback like this:

 (function( $ ) { $.fn.slideshow = function( options ) { options = $.extend({ //... callback: function() {} }, options); var slideTo = function( slide, element ) { var $currentSlide = $( options.slides, element ).eq( slide ); $currentSlide. animate({ opacity: 1 }, options.speed, options.easing, //      options.callback( $currentSlide ) ). siblings( options.slides ). css( "opacity", 0 ); }; //... }; })( jQuery ); 


In this case, the callback is a function from .animate () that accepts the current slide as an argument. Here's how to use it:

 $(function() { $( "#main-slider" ).slideshow({ callback: function( slide ) { var $wrapper = slide.parent(); //       $wrapper.find( ".slide-caption" ).hide(); slide.find( ".slide-caption" ).show( "slow" ); } }); }); 


On pure JS:

 (function() { function Slideshow( element, callback ) { this.callback = callback || function() {}; // Our callback this.el = document.querySelector( element ); this.init(); } Slideshow.prototype = { init: function() { //... this.slides = this.el.querySelectorAll( ".slide" ); //... //... }, _slideTo: function( slide ) { var self = this; var currentSlide = self.slides[slide]; currentSlide.style.opacity = 1; for( var i = 0; i < self.slides.length; i++ ) { var slide = self.slides[i]; if( slide !== currentSlide ) { slide.style.opacity = 0; } } setTimeout( self.callback( currentSlide ), 500 ); //      } }; // })(); 


The callback function is defined as the second parameter of the constructor. You can use it like this:

 document.addEventListener( "DOMContentLoaded", function() { var slider = new Slideshow( "#main-slider", function( slide ) { var wrapper = slide.parentNode; //       var allSlides = wrapper.querySelectorAll( ".slide" ); var caption = slide.querySelector( ".slide-caption" ); caption.classList.add( "visible" ); for( var i = 0; i < allSlides.length; ++i ) { var sld = allSlides[i]; var cpt = sld.querySelector( ".slide-caption" ); if( sld !== slide ) { cpt.classList.remove( "visible" ); } } }); }); 


Examples

jQuery: slideshow with JavaScript callback functions
: slideshow with callback functions

API

: . (YouTube, Vimeo, Flickr), .

, , , :

 <div class="slider" id="main-slider"><!--    --> <div class="slider-wrapper"><!--   --> </div> <div class="slider-nav"><!--  ""  "" --> <button class="slider-previous">  </button> <button class="slider-next">  </button> </div> <div id="spinner"></div><!—  --> </div> 


gif CSS:

 #spinner { border-radius: 50%; border: 2px solid #000; height: 80px; width: 80px; position: absolute; top: 50%; left: 50%; margin: -40px 0 0 -40px; } #spinner:after { content: ''; position: absolute; background-color: #000; top:2px; left: 48%; height: 38px; width: 2px; border-radius: 5px; -webkit-transform-origin: 50% 97%; transform-origin: 50% 97%; -webkit-animation: angular 1s linear infinite; animation: angular 1s linear infinite; } @-webkit-keyframes angular { 0%{-webkit-transform:rotate(0deg);} 100%{-webkit-transform:rotate(360deg);} } @keyframes angular { 0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);} } #spinner:before { content: ''; position: absolute; background-color: #000; top:6px; left: 48%; height: 35px; width: 2px; border-radius: 5px; -webkit-transform-origin: 50% 94%; transform-origin: 50% 94%; -webkit-animation: ptangular 6s linear infinite; animation: ptangular 6s linear infinite; } @-webkit-keyframes ptangular { 0%{-webkit-transform:rotate(0deg);} 100%{-webkit-transform:rotate(360deg);} } @keyframes ptangular { 0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);} } 


:
-
-
-
- HTML
- -
- -

, YouTube. jQuery:

 (function( $ ) { $.fn.slideshow = function( options ) { options = $.extend({ wrapper: ".slider-wrapper", //... loader: "#spinner", //... limit: 5, username: "learncodeacademy" }, options); //... var getVideos = function() { //    YouTube var ytURL = "https://gdata.youtube.com/feeds/api/videos?alt=json&author=" + options.username + "&max-results=" + options.limit; $.getJSON( ytURL, function( videos ) { //     JSON $( options.loader ).hide(); //   var entries = videos.feed.entry; var html = ""; for( var i = 0; i < entries.length; ++i ) { //      HTML var entry = entries[i]; var idURL = entry.id.$t; var idVideo = idURL.replace( "http://gdata.youtube.com/feeds/api/videos/", "" ); var ytEmbedURL = "https://www.youtube.com/embed/" + idVideo + "?rel=0&showinfo=0&controls=0"; html += "<div class='slide'>"; html += "<iframe src='" + ytEmbedURL + "' frameborder='0' allowfullscreen></iframe>"; html += "</div>"; } $( options.wrapper ).html( html ); //  - }); }; return this.each(function() { //... getVideos(); //  - }); }; })( jQuery ); 


JavaScript – JSON:

 (function() { function Slideshow( element ) { this.el = document.querySelector( element ); this.init(); } Slideshow.prototype = { init: function() { this.wrapper = this.el.querySelector( ".slider-wrapper" ); this.loader = this.el.querySelector( "#spinner" ); //... this.limit = 5; this.username = "learncodeacademy"; }, _getJSON: function( url, callback ) { callback = callback || function() {}; var request = new XMLHttpRequest(); request.open( "GET", url, true ); request.send( null ); request.onreadystatechange = function() { if ( request.status == 200 && request.readyState == 4 ) { var data = JSON.parse( request.responseText ); // JSON object callback( data ); } else { console.log( request.status ); } }; }, //... }; })(); 


:

 (function() { function Slideshow( element ) { this.el = document.querySelector( element ); this.init(); } Slideshow.prototype = { init: function() { this.wrapper = this.el.querySelector( ".slider-wrapper" ); this.loader = this.el.querySelector( "#spinner" ); //... this.limit = 5; this.username = "learncodeacademy"; this.actions(); }, _getJSON: function( url, callback ) { callback = callback || function() {}; var request = new XMLHttpRequest(); request.open( "GET", url, true ); request.send( null ); request.onreadystatechange = function() { if ( request.status == 200 && request.readyState == 4 ) { var data = JSON.parse( request.responseText ); // JSON object callback( data ); } else { console.log( request.status ); } }; }, //... getVideos: function() { var self = this; //   YouTube var ytURL = "https://gdata.youtube.com/feeds/api/videos?alt=json&author=" + self.username + "&max-results=" + self.limit; self._getJSON( ytURL, function( videos ) { //     JSON var entries = videos.feed.entry; var html = ""; self.loader.style.display = "none"; //   for( var i = 0; i < entries.length; ++i ) { //      HTML var entry = entries[i]; var idURL = entry.id.$t; var idVideo = idURL.replace( "http://gdata.youtube.com/feeds/api/videos/", "" ); var ytEmbedURL = "https://www.youtube.com/embed/" + idVideo + "?rel=0&showinfo=0&controls=0"; html += "<div class='slide'>"; html += "<iframe src='" + ytEmbedURL + "' frameborder='0' allowfullscreen></iframe>"; html += "</div>"; } self.wrapper.innerHTML = html; //  - }); }, actions: function() { var self = this; self.getVideos(); //  - } }; })(); 


Examples

jQuery: using external API
JavaScript: using external API

Conclusion


Slideshow is an interesting opportunity to improve the user experience. If you do not overdo it, they will allow the user to quickly find the desired content on the site in just a few clicks. Also, a slideshow like Revolution Slider or Nivo Slider show how you can enrich the visual component of the site. But to build such complex projects, you first need to understand the basics.

Examples

Github

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


All Articles