Слайд шоу скрипты. Эффектное слайд-шоу на JavaScript

Если в слайдах содержатся только картинки, можно слегка поменять структуру:

Предыдущий Следующий

Не забудьте добавить осмысленное значение атрибуту alt.

Для использования ссылок на страницы можно сделать следующее:

... ... ... 1 2 3

Предыдущий Следующий 1 2 3

Отметим использование атрибутов «data» – некоторые слайд-шоу умеют вставлять картинки как фон, и эти атрибуты будут использованы в скрипте как места для связи фона и слайда.

Использование списков Семантически верным подходом будет использование элементов списка как слайдов. В этом случае структура будет такой:

Если порядок слайдов хорошо определён (к примеру, в презентации), можно использовать нумерованные списки

CSS Начнём со следующей структуры:

Предыдущий Следующий

Т.к. слайд-шоу будет идти справа налево, то у внешнего контейнера будет фиксированный размер, а внутренний будет шире, поскольку он содержит все слайды. Виден будет первый слайд. Это задаётся через overflow:

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

Стили внутреннего враппера включают:

Большая ширина
- фиксированная высота, максимальная высота слайда
- position: relative, что позволит создать перемещение слайдов
- CSS transition left, что позволит сделать движение плавным. Для простоты мы не указали все префиксы. Для этого также можно использовать CSS transformations (вместе с translation).

У слайдов есть атрибут float, чтобы они выстраивались по одной линии. Позиционируются они относительно, чтобы можно было получить их смещение слева в JS. Его мы используем для создания эффекта скольжения.

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

Хоть мы и задали определённую ширину, в скрипте мы сможем поменять её, умножив количество слайдов на ширину слайда. Никогда не знаешь, какая ширина может потребоваться.

Навигация осуществляется через кнопки “Предыдущий” и “Следующий”. Обнуляем их стили по умолчанию и назначаем свои:

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

При использовании ссылок на страницы вместо кнопок можно сделать следующие стили:

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

Эти классы будут назначены из скрипта динамически.

Такой подход годится для эффекта скольжения. Если мы хотим достичь эффекта исчезновения и появления, надо поменять стили, поскольку float добавляет горизонтальные отступы между слайдами. То есть, слайды на одной линии нам не нужны – нам нужна "пачка" слайдов:

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 >
Для скрытия слайдов мы используем свойство opacity, поскольку программы для чтения данных с экрана пропускают содержимое элементов, у которых установлен display: none (см. CSS in Action: Invisible Content Just for Screen Reader Users).

Благодаря контекстному позиционированию CSS мы создали "пачку" слайдов, где последний слайд в исходнике оказывается впереди других. Но нам не это нужно. Для сохранения порядка слайдов нам надо спрятать все слайды, кроме первого.

JS задействует CSS transition, меняя значение свойства opacity у текущего слайда, и обнуляя это значение у всех остальных.

Код на JavaScriptСлайд-шоу без разбивки на страницы Слайд-шоу без разбивки на страницы работают по нажатию кнопок “Следующий” и “Предыдущий”. Их можно рассматривать как операторы инкремента и декремента. Всегда есть указатель (или курсор), который будет увеличен или уменьшен каждый раз по нажатию на кнопки. Начальное его значение 0, а цель – выбирать текущий слайд так же, как выбираются элементы массива.

Поэтому, когда мы первый раз нажимаем Следующий, указатель увеличивается на 1 и мы получаем второй слайд. Нажимая на Предыдущий, мы уменьшаем указатель и получаем первый слайд. И т.д.

Вместе с указателем мы используем метод jQuery .eq() для получения текущего слайда. На чистом JS это выглядит так:

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; //... } };

Помните - NodeList использует индексы так же, как массив. Ещё один способ выбрать текущий слайд – селекторы CSS3:

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

Селектор CSS3:nth-child() считает элементы с 1, поэтому нужно добавить единичку к указателю. После выбора слайда его родительский контейнер надо сдвинуть справа налево. В jQuery можно использовать метод.animate():

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

В обычном JS нет метода.animate(), поэтому мы используем переходы CSS:

Slider-wrapper { position: relative; // обязательно transition: left 500ms linear; }

Теперь можно менять свойство left динамически через объект style:

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; this.wrapper.style.left = "-" + currentSlide.offsetLeft + "px"; } };

Теперь надо сделать событие клика для каждого элемента управления. В jQuery можно взять метод.on(), а в чистом JS - метод addEventListener().

Также надо проверять, не достиг ли указатель границ списка – 0 для “Предыдущий” и общего количества слайдов для “Следующий”. В каждом случае надо прятать соответствующую кнопку:

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

А на чистом JS это выглядит так:

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

Слайд-шоу с разделением на страницы В таком слайд-шоу каждая ссылка отвечает за один слайд, поэтому указатель не нужен. Анимации не меняются – меняется способ, которым пользователь перемещается по слайдам. Для jQuery у нас будет следующий код:

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

В этом случае каждый анкор соответствует ID определённого слайда. В чистом JS можно использовать как его, так и атрибут data, хранящий числовой индекс слайдов внутри 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 = ""; } } } };

Начиная с IE10 можно управлять классами через classList:

Link.classList.add("current");

А с IE11 атрибуты data можно получать через свойство dataset:

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

Слайд-шоу с разделением на страницы и элементами управления Такие слайд-шоу представляют некоторую сложность для кода – приходится комбинировать использование указателя и хэшей страниц. То есть, текущий слайд нужно выбирать как на основании позиции указателя, так и на основании слайда, выбранного через ссылки.

Синхронизировать это можно через номерной индекс каждой ссылки в DOM. Один линк – один слайд, поэтому их индексы будут 0, 1, 2 и т.д.

На jQuery код будет такой:

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

Сразу видно, что изменилась видимость курсора – теперь индекс объявлен как свойство объекта слайд-шоу. Таким образом мы избегаем проблем с областью видимости, которые могут быть созданы обратными вызовами в jQuery. Теперь курсор доступен везде, и даже вне пространства имён плагина, поскольку он объявлен как публичное свойство объекта slideshow.

Метод.index() даёт числовой индекс каждой ссылки.

В чистом JS нет такого метода, так что проще использовать атрибуты данных:

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

Теперь мы можем соединить наши процедуры со ссылками и использовать только что созданные атрибуты данных:

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

Разбираемся с размерами Вернёмся-ка к следующему правилу CSS:

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

Если у нас слайдов будет много, то 9999 может не хватить. Нужно на лету подстраивать размеры для слайдов на основании ширины каждого из них и их количества.

На jQuery это просто:

// Слайд-шоу на всю ширину return this.each(function() { var $element = $(this), total = $(options.slides).length; //... $(options.slides, $element).width($(window).width()); $(options.wrapper, $element).width($(window).width() * total); //... });

Берём ширину окна и задаём ширину каждого слайда. Общая ширина внутреннего враппера получается перемножением ширины окна и количества слайдов.

// Слайд-шоу фиксированной ширины return this.each(function() { var $element = $(this), total = $(options.slides).length; //... $(options.wrapper, $element).width($(options.slides).eq(0).width() * total); //... });

Здесь начальная ширина задана шириной каждого слайда. Нужно только задать общую ширину враппера.

Теперь внутренний контейнер достаточно широк. На чистом JS это делается примерно так же:

// Слайд-шоу на всю ширину 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.offsetWidth; // Single slide"s width var wrapperWidth = slideWidth * self.total; self.wrapper.style.width = wrapperWidth + "px"; }, //... };

Эффекты исчезновения Эффекты исчезновения (fade) часто используются в слайд-шоу. Текущий слайд исчезает, и появляется следующий. У jQuery есть методы fadeIn() и fadeOut(), которые работают как со свойством opacity, так и с display, поэтому элемент удаляется из страницы по завершению анимации (display:none).

В чистом JS лучше всего работать со свойством opacity и использовать стек позиционирования CSS. Тогда изначально слайд будет видимым (opacity: 1), а другие - спрятаны (opacity:0).

Следующий набор стилей демонстрирует такой способ:

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

В чистом JS необходимо зарегистрировать переход CSS каждого слайда:

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

С jQuery для использования методов fadeIn() и fadeOut() надо менять opacity и display:

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

В jQuery код следующий:

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

При анимации opacity нужно также поменять значения этого свойства для остальных слайдов.

В JavaScript это будет:

Slideshow.prototype = { //... _slideTo: function(slide) { var currentSlide = this.slides; 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; } } }, //... };

Медийные элементы: видео Мы можем включать видео в слайд-шоу. Вот пример слайд-шоу с видео от Vimeo:

Видео включаются через iframe. Это такой же заменяемый inline-block, как и картинка. Заменяемый – потому, что содержимое взято из внешнего источника.

Чтобы создать полностраничное слайд-шоу, надо поменять стили следующим образом:

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%; /* Высота и ширина на полную */ }

Автоматические слайд-шоу Автоматические слайд-шоу используют таймеры. При каждом обратном вызове функции по таймеру setInterval() курсор будет увеличиваться на 1 и таким образом будет выбираться следующий слайд.

Когда курсор достигнет максимального количества слайдов, его надо обнулить.

Бесконечные слайд-шоу быстро надоедают пользователям. Лучше всего останавливать анимацию, когда пользователь наводит на неё курсор мыши, и восстанавливать, когда курсор уходит.

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

Оба параметра метода.stop() установлены в true, т.к. нам не нужно создавать очередь анимации из нашей последовательности.

На чистом JS код становится проще. Регистрируем переход CSS для каждого слайда с определённой длительности:

Slide { transition: opacity 3s linear; /* 3 секунды = 3000 миллисекунд */ }

И код будет следующим:

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

Навигация с клавиатуры Продвинутые слайд-шоу предлагают управление с клавиатуры, т.е. перелистывание слайдов по нажатию клавиш. Для нас это просто означает необходимость регистрации обработки события нажатия на клавиши.

Для этого мы обратимся к свойству 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, а можно было бы просто вызвать этот метод.

Обратные вызовы Было бы неплохо уметь прикреплять к любому действию слайд-шоу некоторый код, который бы выполнялся, когда это действие производится. В этом и состоит назначение функций обратного вызова – они выполняются только, когда происходит определённое действие. Допустим, у нашего слайд-шоу есть подписи и они по умолчанию скрыты. В момент анимации нам надо показать подпись для текущего слайда или даже что-нибудь сделать с ним.

В jQuery можно создать обратный вызов так:

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

В этом случае обратный вызов – это функция из.animate(), которая принимает текущий слайд как аргумент. Вот, как это можно использовать:

$(function() { $("#main-slider").slideshow({ callback: function(slide) { var $wrapper = slide.parent(); // Показывает текущую подпись и прячет остальные $wrapper.find(".slide-caption").hide(); slide.find(".slide-caption").show("slow"); } }); });

На чистом 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; 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); // Вызывает функцию по окончанию перехода } }; // })();

Функция обратного вызова определена как второй параметр конструктора. Использовать её можно так:

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

Внешние API Пока наш сценарий работы прост: все слайды уже есть в документе. Если нам надо вставлять в него данные снаружи (YouTube, Vimeo, Flickr), нам нужно на лету заполнять слайды по мере получения внешнего контента.

Так как ответ со стороннего сервера может быть не немедленным, надо вставлять анимацию загрузки, чтобы показать, что процесс идёт:

Предыдущий Следующий

Это может быть 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 += ""; html += ""; html += ""; } $(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 += ""; html += ""; html += ""; } self.wrapper.innerHTML = html; // Выводим слайд-шоу }); }, actions: function() { var self = this; self.getVideos(); // Обрабатываем слайд-шоу } }; })(); Добавить метки

Если в слайдах содержатся только картинки, можно слегка поменять структуру:

Предыдущий Следующий

Не забудьте добавить осмысленное значение атрибуту alt.

Для использования ссылок на страницы можно сделать следующее:

... ... ... 1 2 3

Предыдущий Следующий 1 2 3

Отметим использование атрибутов «data» – некоторые слайд-шоу умеют вставлять картинки как фон, и эти атрибуты будут использованы в скрипте как места для связи фона и слайда.

Использование списков Семантически верным подходом будет использование элементов списка как слайдов. В этом случае структура будет такой:

Если порядок слайдов хорошо определён (к примеру, в презентации), можно использовать нумерованные списки

CSS Начнём со следующей структуры:

Предыдущий Следующий

Т.к. слайд-шоу будет идти справа налево, то у внешнего контейнера будет фиксированный размер, а внутренний будет шире, поскольку он содержит все слайды. Виден будет первый слайд. Это задаётся через overflow:

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

Стили внутреннего враппера включают:

Большая ширина
- фиксированная высота, максимальная высота слайда
- position: relative, что позволит создать перемещение слайдов
- CSS transition left, что позволит сделать движение плавным. Для простоты мы не указали все префиксы. Для этого также можно использовать CSS transformations (вместе с translation).

У слайдов есть атрибут float, чтобы они выстраивались по одной линии. Позиционируются они относительно, чтобы можно было получить их смещение слева в JS. Его мы используем для создания эффекта скольжения.

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

Хоть мы и задали определённую ширину, в скрипте мы сможем поменять её, умножив количество слайдов на ширину слайда. Никогда не знаешь, какая ширина может потребоваться.

Навигация осуществляется через кнопки “Предыдущий” и “Следующий”. Обнуляем их стили по умолчанию и назначаем свои:

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

При использовании ссылок на страницы вместо кнопок можно сделать следующие стили:

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

Эти классы будут назначены из скрипта динамически.

Такой подход годится для эффекта скольжения. Если мы хотим достичь эффекта исчезновения и появления, надо поменять стили, поскольку float добавляет горизонтальные отступы между слайдами. То есть, слайды на одной линии нам не нужны – нам нужна "пачка" слайдов:

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 >
Для скрытия слайдов мы используем свойство opacity, поскольку программы для чтения данных с экрана пропускают содержимое элементов, у которых установлен display: none (см. CSS in Action: Invisible Content Just for Screen Reader Users).

Благодаря контекстному позиционированию CSS мы создали "пачку" слайдов, где последний слайд в исходнике оказывается впереди других. Но нам не это нужно. Для сохранения порядка слайдов нам надо спрятать все слайды, кроме первого.

JS задействует CSS transition, меняя значение свойства opacity у текущего слайда, и обнуляя это значение у всех остальных.

Код на JavaScriptСлайд-шоу без разбивки на страницы Слайд-шоу без разбивки на страницы работают по нажатию кнопок “Следующий” и “Предыдущий”. Их можно рассматривать как операторы инкремента и декремента. Всегда есть указатель (или курсор), который будет увеличен или уменьшен каждый раз по нажатию на кнопки. Начальное его значение 0, а цель – выбирать текущий слайд так же, как выбираются элементы массива.

Поэтому, когда мы первый раз нажимаем Следующий, указатель увеличивается на 1 и мы получаем второй слайд. Нажимая на Предыдущий, мы уменьшаем указатель и получаем первый слайд. И т.д.

Вместе с указателем мы используем метод jQuery .eq() для получения текущего слайда. На чистом JS это выглядит так:

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; //... } };

Помните - NodeList использует индексы так же, как массив. Ещё один способ выбрать текущий слайд – селекторы CSS3:

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

Селектор CSS3:nth-child() считает элементы с 1, поэтому нужно добавить единичку к указателю. После выбора слайда его родительский контейнер надо сдвинуть справа налево. В jQuery можно использовать метод.animate():

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

В обычном JS нет метода.animate(), поэтому мы используем переходы CSS:

Slider-wrapper { position: relative; // обязательно transition: left 500ms linear; }

Теперь можно менять свойство left динамически через объект style:

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; this.wrapper.style.left = "-" + currentSlide.offsetLeft + "px"; } };

Теперь надо сделать событие клика для каждого элемента управления. В jQuery можно взять метод.on(), а в чистом JS - метод addEventListener().

Также надо проверять, не достиг ли указатель границ списка – 0 для “Предыдущий” и общего количества слайдов для “Следующий”. В каждом случае надо прятать соответствующую кнопку:

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

А на чистом JS это выглядит так:

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

Слайд-шоу с разделением на страницы В таком слайд-шоу каждая ссылка отвечает за один слайд, поэтому указатель не нужен. Анимации не меняются – меняется способ, которым пользователь перемещается по слайдам. Для jQuery у нас будет следующий код:

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

В этом случае каждый анкор соответствует ID определённого слайда. В чистом JS можно использовать как его, так и атрибут data, хранящий числовой индекс слайдов внутри 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 = ""; } } } };

Начиная с IE10 можно управлять классами через classList:

Link.classList.add("current");

А с IE11 атрибуты data можно получать через свойство dataset:

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

Слайд-шоу с разделением на страницы и элементами управления Такие слайд-шоу представляют некоторую сложность для кода – приходится комбинировать использование указателя и хэшей страниц. То есть, текущий слайд нужно выбирать как на основании позиции указателя, так и на основании слайда, выбранного через ссылки.

Синхронизировать это можно через номерной индекс каждой ссылки в DOM. Один линк – один слайд, поэтому их индексы будут 0, 1, 2 и т.д.

На jQuery код будет такой:

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

Сразу видно, что изменилась видимость курсора – теперь индекс объявлен как свойство объекта слайд-шоу. Таким образом мы избегаем проблем с областью видимости, которые могут быть созданы обратными вызовами в jQuery. Теперь курсор доступен везде, и даже вне пространства имён плагина, поскольку он объявлен как публичное свойство объекта slideshow.

Метод.index() даёт числовой индекс каждой ссылки.

В чистом JS нет такого метода, так что проще использовать атрибуты данных:

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

Теперь мы можем соединить наши процедуры со ссылками и использовать только что созданные атрибуты данных:

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

Разбираемся с размерами Вернёмся-ка к следующему правилу CSS:

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

Если у нас слайдов будет много, то 9999 может не хватить. Нужно на лету подстраивать размеры для слайдов на основании ширины каждого из них и их количества.

На jQuery это просто:

// Слайд-шоу на всю ширину return this.each(function() { var $element = $(this), total = $(options.slides).length; //... $(options.slides, $element).width($(window).width()); $(options.wrapper, $element).width($(window).width() * total); //... });

Берём ширину окна и задаём ширину каждого слайда. Общая ширина внутреннего враппера получается перемножением ширины окна и количества слайдов.

// Слайд-шоу фиксированной ширины return this.each(function() { var $element = $(this), total = $(options.slides).length; //... $(options.wrapper, $element).width($(options.slides).eq(0).width() * total); //... });

Здесь начальная ширина задана шириной каждого слайда. Нужно только задать общую ширину враппера.

Теперь внутренний контейнер достаточно широк. На чистом JS это делается примерно так же:

// Слайд-шоу на всю ширину 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.offsetWidth; // Single slide"s width var wrapperWidth = slideWidth * self.total; self.wrapper.style.width = wrapperWidth + "px"; }, //... };

Эффекты исчезновения Эффекты исчезновения (fade) часто используются в слайд-шоу. Текущий слайд исчезает, и появляется следующий. У jQuery есть методы fadeIn() и fadeOut(), которые работают как со свойством opacity, так и с display, поэтому элемент удаляется из страницы по завершению анимации (display:none).

В чистом JS лучше всего работать со свойством opacity и использовать стек позиционирования CSS. Тогда изначально слайд будет видимым (opacity: 1), а другие - спрятаны (opacity:0).

Следующий набор стилей демонстрирует такой способ:

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

В чистом JS необходимо зарегистрировать переход CSS каждого слайда:

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

С jQuery для использования методов fadeIn() и fadeOut() надо менять opacity и display:

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

В jQuery код следующий:

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

При анимации opacity нужно также поменять значения этого свойства для остальных слайдов.

В JavaScript это будет:

Slideshow.prototype = { //... _slideTo: function(slide) { var currentSlide = this.slides; 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; } } }, //... };

Медийные элементы: видео Мы можем включать видео в слайд-шоу. Вот пример слайд-шоу с видео от Vimeo:

Видео включаются через iframe. Это такой же заменяемый inline-block, как и картинка. Заменяемый – потому, что содержимое взято из внешнего источника.

Чтобы создать полностраничное слайд-шоу, надо поменять стили следующим образом:

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%; /* Высота и ширина на полную */ }

Автоматические слайд-шоу Автоматические слайд-шоу используют таймеры. При каждом обратном вызове функции по таймеру setInterval() курсор будет увеличиваться на 1 и таким образом будет выбираться следующий слайд.

Когда курсор достигнет максимального количества слайдов, его надо обнулить.

Бесконечные слайд-шоу быстро надоедают пользователям. Лучше всего останавливать анимацию, когда пользователь наводит на неё курсор мыши, и восстанавливать, когда курсор уходит.

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

Оба параметра метода.stop() установлены в true, т.к. нам не нужно создавать очередь анимации из нашей последовательности.

На чистом JS код становится проще. Регистрируем переход CSS для каждого слайда с определённой длительности:

Slide { transition: opacity 3s linear; /* 3 секунды = 3000 миллисекунд */ }

И код будет следующим:

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

Навигация с клавиатуры Продвинутые слайд-шоу предлагают управление с клавиатуры, т.е. перелистывание слайдов по нажатию клавиш. Для нас это просто означает необходимость регистрации обработки события нажатия на клавиши.

Для этого мы обратимся к свойству 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, а можно было бы просто вызвать этот метод.

Обратные вызовы Было бы неплохо уметь прикреплять к любому действию слайд-шоу некоторый код, который бы выполнялся, когда это действие производится. В этом и состоит назначение функций обратного вызова – они выполняются только, когда происходит определённое действие. Допустим, у нашего слайд-шоу есть подписи и они по умолчанию скрыты. В момент анимации нам надо показать подпись для текущего слайда или даже что-нибудь сделать с ним.

В jQuery можно создать обратный вызов так:

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

В этом случае обратный вызов – это функция из.animate(), которая принимает текущий слайд как аргумент. Вот, как это можно использовать:

$(function() { $("#main-slider").slideshow({ callback: function(slide) { var $wrapper = slide.parent(); // Показывает текущую подпись и прячет остальные $wrapper.find(".slide-caption").hide(); slide.find(".slide-caption").show("slow"); } }); });

На чистом 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; 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); // Вызывает функцию по окончанию перехода } }; // })();

Функция обратного вызова определена как второй параметр конструктора. Использовать её можно так:

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

Внешние API Пока наш сценарий работы прост: все слайды уже есть в документе. Если нам надо вставлять в него данные снаружи (YouTube, Vimeo, Flickr), нам нужно на лету заполнять слайды по мере получения внешнего контента.

Так как ответ со стороннего сервера может быть не немедленным, надо вставлять анимацию загрузки, чтобы показать, что процесс идёт:

Предыдущий Следующий

Это может быть 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 += ""; html += ""; html += ""; } $(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 += ""; html += ""; html += ""; } self.wrapper.innerHTML = html; // Выводим слайд-шоу }); }, actions: function() { var self = this; self.getVideos(); // Обрабатываем слайд-шоу } }; })(); Добавить метки

Если в слайдах содержатся только картинки, можно слегка поменять структуру:

Предыдущий Следующий

Не забудьте добавить осмысленное значение атрибуту alt.

Для использования ссылок на страницы можно сделать следующее:

... ... ... 1 2 3

Предыдущий Следующий 1 2 3

Отметим использование атрибутов «data» – некоторые слайд-шоу умеют вставлять картинки как фон, и эти атрибуты будут использованы в скрипте как места для связи фона и слайда.

Использование списков Семантически верным подходом будет использование элементов списка как слайдов. В этом случае структура будет такой:

Если порядок слайдов хорошо определён (к примеру, в презентации), можно использовать нумерованные списки

CSS Начнём со следующей структуры:

Предыдущий Следующий

Т.к. слайд-шоу будет идти справа налево, то у внешнего контейнера будет фиксированный размер, а внутренний будет шире, поскольку он содержит все слайды. Виден будет первый слайд. Это задаётся через overflow:

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

Стили внутреннего враппера включают:

Большая ширина
- фиксированная высота, максимальная высота слайда
- position: relative, что позволит создать перемещение слайдов
- CSS transition left, что позволит сделать движение плавным. Для простоты мы не указали все префиксы. Для этого также можно использовать CSS transformations (вместе с translation).

У слайдов есть атрибут float, чтобы они выстраивались по одной линии. Позиционируются они относительно, чтобы можно было получить их смещение слева в JS. Его мы используем для создания эффекта скольжения.

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

Хоть мы и задали определённую ширину, в скрипте мы сможем поменять её, умножив количество слайдов на ширину слайда. Никогда не знаешь, какая ширина может потребоваться.

Навигация осуществляется через кнопки “Предыдущий” и “Следующий”. Обнуляем их стили по умолчанию и назначаем свои:

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

При использовании ссылок на страницы вместо кнопок можно сделать следующие стили:

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

Эти классы будут назначены из скрипта динамически.

Такой подход годится для эффекта скольжения. Если мы хотим достичь эффекта исчезновения и появления, надо поменять стили, поскольку float добавляет горизонтальные отступы между слайдами. То есть, слайды на одной линии нам не нужны – нам нужна "пачка" слайдов:

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 >
Для скрытия слайдов мы используем свойство opacity, поскольку программы для чтения данных с экрана пропускают содержимое элементов, у которых установлен display: none (см. CSS in Action: Invisible Content Just for Screen Reader Users).

Благодаря контекстному позиционированию CSS мы создали "пачку" слайдов, где последний слайд в исходнике оказывается впереди других. Но нам не это нужно. Для сохранения порядка слайдов нам надо спрятать все слайды, кроме первого.

JS задействует CSS transition, меняя значение свойства opacity у текущего слайда, и обнуляя это значение у всех остальных.

Код на JavaScriptСлайд-шоу без разбивки на страницы Слайд-шоу без разбивки на страницы работают по нажатию кнопок “Следующий” и “Предыдущий”. Их можно рассматривать как операторы инкремента и декремента. Всегда есть указатель (или курсор), который будет увеличен или уменьшен каждый раз по нажатию на кнопки. Начальное его значение 0, а цель – выбирать текущий слайд так же, как выбираются элементы массива.

Поэтому, когда мы первый раз нажимаем Следующий, указатель увеличивается на 1 и мы получаем второй слайд. Нажимая на Предыдущий, мы уменьшаем указатель и получаем первый слайд. И т.д.

Вместе с указателем мы используем метод jQuery .eq() для получения текущего слайда. На чистом JS это выглядит так:

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; //... } };

Помните - NodeList использует индексы так же, как массив. Ещё один способ выбрать текущий слайд – селекторы CSS3:

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

Селектор CSS3:nth-child() считает элементы с 1, поэтому нужно добавить единичку к указателю. После выбора слайда его родительский контейнер надо сдвинуть справа налево. В jQuery можно использовать метод.animate():

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

В обычном JS нет метода.animate(), поэтому мы используем переходы CSS:

Slider-wrapper { position: relative; // обязательно transition: left 500ms linear; }

Теперь можно менять свойство left динамически через объект style:

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; this.wrapper.style.left = "-" + currentSlide.offsetLeft + "px"; } };

Теперь надо сделать событие клика для каждого элемента управления. В jQuery можно взять метод.on(), а в чистом JS - метод addEventListener().

Также надо проверять, не достиг ли указатель границ списка – 0 для “Предыдущий” и общего количества слайдов для “Следующий”. В каждом случае надо прятать соответствующую кнопку:

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

А на чистом JS это выглядит так:

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

Слайд-шоу с разделением на страницы В таком слайд-шоу каждая ссылка отвечает за один слайд, поэтому указатель не нужен. Анимации не меняются – меняется способ, которым пользователь перемещается по слайдам. Для jQuery у нас будет следующий код:

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

В этом случае каждый анкор соответствует ID определённого слайда. В чистом JS можно использовать как его, так и атрибут data, хранящий числовой индекс слайдов внутри 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 = ""; } } } };

Начиная с IE10 можно управлять классами через classList:

Link.classList.add("current");

А с IE11 атрибуты data можно получать через свойство dataset:

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

Слайд-шоу с разделением на страницы и элементами управления Такие слайд-шоу представляют некоторую сложность для кода – приходится комбинировать использование указателя и хэшей страниц. То есть, текущий слайд нужно выбирать как на основании позиции указателя, так и на основании слайда, выбранного через ссылки.

Синхронизировать это можно через номерной индекс каждой ссылки в DOM. Один линк – один слайд, поэтому их индексы будут 0, 1, 2 и т.д.

На jQuery код будет такой:

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

Сразу видно, что изменилась видимость курсора – теперь индекс объявлен как свойство объекта слайд-шоу. Таким образом мы избегаем проблем с областью видимости, которые могут быть созданы обратными вызовами в jQuery. Теперь курсор доступен везде, и даже вне пространства имён плагина, поскольку он объявлен как публичное свойство объекта slideshow.

Метод.index() даёт числовой индекс каждой ссылки.

В чистом JS нет такого метода, так что проще использовать атрибуты данных:

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

Теперь мы можем соединить наши процедуры со ссылками и использовать только что созданные атрибуты данных:

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

Разбираемся с размерами Вернёмся-ка к следующему правилу CSS:

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

Если у нас слайдов будет много, то 9999 может не хватить. Нужно на лету подстраивать размеры для слайдов на основании ширины каждого из них и их количества.

На jQuery это просто:

// Слайд-шоу на всю ширину return this.each(function() { var $element = $(this), total = $(options.slides).length; //... $(options.slides, $element).width($(window).width()); $(options.wrapper, $element).width($(window).width() * total); //... });

Берём ширину окна и задаём ширину каждого слайда. Общая ширина внутреннего враппера получается перемножением ширины окна и количества слайдов.

// Слайд-шоу фиксированной ширины return this.each(function() { var $element = $(this), total = $(options.slides).length; //... $(options.wrapper, $element).width($(options.slides).eq(0).width() * total); //... });

Здесь начальная ширина задана шириной каждого слайда. Нужно только задать общую ширину враппера.

Теперь внутренний контейнер достаточно широк. На чистом JS это делается примерно так же:

// Слайд-шоу на всю ширину 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.offsetWidth; // Single slide"s width var wrapperWidth = slideWidth * self.total; self.wrapper.style.width = wrapperWidth + "px"; }, //... };

Эффекты исчезновения Эффекты исчезновения (fade) часто используются в слайд-шоу. Текущий слайд исчезает, и появляется следующий. У jQuery есть методы fadeIn() и fadeOut(), которые работают как со свойством opacity, так и с display, поэтому элемент удаляется из страницы по завершению анимации (display:none).

В чистом JS лучше всего работать со свойством opacity и использовать стек позиционирования CSS. Тогда изначально слайд будет видимым (opacity: 1), а другие - спрятаны (opacity:0).

Следующий набор стилей демонстрирует такой способ:

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

В чистом JS необходимо зарегистрировать переход CSS каждого слайда:

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

С jQuery для использования методов fadeIn() и fadeOut() надо менять opacity и display:

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

В jQuery код следующий:

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

При анимации opacity нужно также поменять значения этого свойства для остальных слайдов.

В JavaScript это будет:

Slideshow.prototype = { //... _slideTo: function(slide) { var currentSlide = this.slides; 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; } } }, //... };

Медийные элементы: видео Мы можем включать видео в слайд-шоу. Вот пример слайд-шоу с видео от Vimeo:

Видео включаются через iframe. Это такой же заменяемый inline-block, как и картинка. Заменяемый – потому, что содержимое взято из внешнего источника.

Чтобы создать полностраничное слайд-шоу, надо поменять стили следующим образом:

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%; /* Высота и ширина на полную */ }

Автоматические слайд-шоу Автоматические слайд-шоу используют таймеры. При каждом обратном вызове функции по таймеру setInterval() курсор будет увеличиваться на 1 и таким образом будет выбираться следующий слайд.

Когда курсор достигнет максимального количества слайдов, его надо обнулить.

Бесконечные слайд-шоу быстро надоедают пользователям. Лучше всего останавливать анимацию, когда пользователь наводит на неё курсор мыши, и восстанавливать, когда курсор уходит.

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

Оба параметра метода.stop() установлены в true, т.к. нам не нужно создавать очередь анимации из нашей последовательности.

На чистом JS код становится проще. Регистрируем переход CSS для каждого слайда с определённой длительности:

Slide { transition: opacity 3s linear; /* 3 секунды = 3000 миллисекунд */ }

И код будет следующим:

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

Навигация с клавиатуры Продвинутые слайд-шоу предлагают управление с клавиатуры, т.е. перелистывание слайдов по нажатию клавиш. Для нас это просто означает необходимость регистрации обработки события нажатия на клавиши.

Для этого мы обратимся к свойству 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, а можно было бы просто вызвать этот метод.

Обратные вызовы Было бы неплохо уметь прикреплять к любому действию слайд-шоу некоторый код, который бы выполнялся, когда это действие производится. В этом и состоит назначение функций обратного вызова – они выполняются только, когда происходит определённое действие. Допустим, у нашего слайд-шоу есть подписи и они по умолчанию скрыты. В момент анимации нам надо показать подпись для текущего слайда или даже что-нибудь сделать с ним.

В jQuery можно создать обратный вызов так:

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

В этом случае обратный вызов – это функция из.animate(), которая принимает текущий слайд как аргумент. Вот, как это можно использовать:

$(function() { $("#main-slider").slideshow({ callback: function(slide) { var $wrapper = slide.parent(); // Показывает текущую подпись и прячет остальные $wrapper.find(".slide-caption").hide(); slide.find(".slide-caption").show("slow"); } }); });

На чистом 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; 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); // Вызывает функцию по окончанию перехода } }; // })();

Функция обратного вызова определена как второй параметр конструктора. Использовать её можно так:

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

Внешние API Пока наш сценарий работы прост: все слайды уже есть в документе. Если нам надо вставлять в него данные снаружи (YouTube, Vimeo, Flickr), нам нужно на лету заполнять слайды по мере получения внешнего контента.

Так как ответ со стороннего сервера может быть не немедленным, надо вставлять анимацию загрузки, чтобы показать, что процесс идёт:

Предыдущий Следующий

Это может быть 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 += ""; html += ""; html += ""; } $(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 += ""; html += ""; html += ""; } self.wrapper.innerHTML = html; // Выводим слайд-шоу }); }, actions: function() { var self = this; self.getVideos(); // Обрабатываем слайд-шоу } }; })(); Добавить метки

1. Превосходное jQuery слайд-шоу

Большое эффектное слайд-шоу с использованием jQuery технологий.

2. jQuery плагин «Scale Carousel»

Масштабируемое слайд-шоу с использованием jQuery. Вы сможете задать размеры для слайд-шоу, которые вам больше всего подходят.

3. jQuery плагин «slideJS»

Слайдер изображений с текстовым описанием.

4. Плагин «JSliderNews» 5. CSS3 jQuery слайдер

При наведении курсора на стрелки навигации появляется круглая миниатюра следующего слайда.

6. Симпатичный jQuery слайдер «Presentation Cycle»

jQuery слайдер с индикатором загрузки изображений. Предусмотрена автоматическая смена слайдов.

7. jQuery плагин «Parallax Slider»

Слайдер с объемным фоновым эффектом. Изюминка этого слайдера в движение фона, который состоит из нескольких слоев, каждый из которых прокручивается с различной скоростью. В итоге получается имитация объемного эффекта. Выглядит очень красиво, вы можете сами в этом убедиться. Более плавно эффект отображается в таких браузерах как: Opera, Google Chrome, IE.

8. Свежий, легкий jQuery слайдер «bxSlider 3.0»

На демонстрационной странице в разделе «examples» вы сможете найти ссылки на все возможные варианты использования этого плагина.

9. jQuery слайдер изображений, плагин «slideJS»

Стильный jQuery слайдер, безусловно сможет украсить ваш проект.

10. jQuery плагин слайд-шоу «Easy Slides» v1.1

Простой в использовании JQuery плагин для создания слайд-шоу.

11. Плагин «jQuery Slidy»

Легкий jQuery плагин в различном исполнении. Предусмотрена автоматическая смена слайдов.

12. jQuery CSS галерея с автоматической сменой слайдов

Если посетитель в течении определенного времени не нажмет на стрелки «Вперед» или «Назад», то галерея начнет прокручиваться автоматически.

13. jQuery слайдер «Nivo Slider»

Очень профессиональный качественный легкий плагин с валидным кодом. Предусмотрено много различных эффектов смены слайдов.

14. jQuery слайдер «MobilySlider»

Свежий слайдер. jQuery слайдер с различными эффектами смены изображений.

15. jQuery Плагин «Slider²»

Легкий слайдер с автоматической сменой слайдов.

16. Свежий javascript слайдер

Слайдер с автоматической сменой изображений.

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

jQuery CSS слайдер изображений с использованием плагина NivoSlider .

19. jQuery слайдер«jShowOff»

Плагин для ротации содержимого. Три варианта использования: без навигации (с автоматической сменой в формате слайд-шоу), с навигацией в виде кнопок, с навигацией в виде миниатюр изображений.

20. Плагин «Shutter Effect Portfolio»

Свежий jQuery плагин для оформления портфолио фотографа. В галерее реализован интересный эффект смены изображений. Фотографии сменяют друг друга с эффектом похожим на работу затвора объектива.

21. Легкий javascript CSS слайдер «TinySlider 2»

Реализация слайдера изображений с использованием javascript и CSS.

22. Обалденный слайдер «Tinycircleslider»

Стильный круглый слайдер. Переход между изображениями осуществляется с помощью перетаскивания по окружности ползунка в виде красного круга. Отлично впишется в ваш сайт, если вы в дизайне используете круглые элементы.

23. Слайдер изображений на jQuery

Легкий слайдер «Slider Kit». Слайдер представлен в различном исполнении: вертикальный и горизонтальный. Также реализованы различные виды навигации между изображениями: с помощью кнопок «Вперед» и «Назад», с помощью колеса мыши, с помощью клика мыши по слайду.

24. Галерея с миниатюрами «Slider Kit»

Галерея «Slider Kit». Прокрутка миниатюр осуществляется как в вертикальном так и горизонтальном направлении. Переход между изображениями осуществляется с помощью: колеса мыши, щелчка мыши или наведения курсора на миниатюру.

25. jQuery слайдер содержимого «Slider Kit»

Вертикальный и горизонтальный слайдер контента на jQuery.

26. jQuery слайд-шоу «Slider Kit»

Слайд-шоу с автоматической сменой слайдов.

27. Легкий профессиональный javascript CSS3 слайдер

Аккуратный слайдер на jQuery и CSS3, созданный в 2011 году.

jQuery слайд-шоу с миниатюрами.

29. Простое jQuery слайд-шоу

Слайд-шоу с кнопками навигации.

30. Потрясное слайд-шоу jQuery «Skitter»

jQuery плагин «Skitter» для создания потрясающего слайд-шоу. Плагин поддерживает 22 (!) вида различных анимационных эффектов при смене изображений. Может работать с двумя вариантами навигации по слайдам: с помощью номеров слайдов и с помощью миниатюр. Обязательно посмотрите демонстрацию, очень качественная находка. Используемые технологии: CSS, HTML, jQuery, PHP.

31. Слайд-шоу «Awkward»

Функциональное слайд-шоу. В виде слайдов могут выступать: простые изображения, изображения с подписями, изображения с всплывающими подсказками, видео-ролики. Для навигации можно использовать стрелки, ссылки на номера слайдов и клавиши вправо/влево на клавиатуре. Слайд-шоу выполнено в нескольких вариантах: с миниатюрами и без них. Для просмотра всех вариантов пройдитесь по ссылкам Demo #1 - Demo #6 расположенным сверху на демонстрационной странице.

Очень оригинальное оформление слайдера изображений, напоминающее веер. Анимированная смена слайдов. Навигация между изображениями осуществляется с помощью стрелок. Предусмотрена также автоматическая смена, которую можно включать и выключать с помощью кнопки Play/Pause, расположенной сверху.

Анимированный jQuery слайдер. Фоновые изображения автоматически масштабируются при изменении размеров окна браузера. Для каждого изображения выплывает блок с описанием.

34. «Flux Slider» слайдер на jQuery и CSS3

Новый jQuery слайдер. Несколько классных анимированных эффектов при смене слайдов.

35. jQuery плагин «jSwitch»

Анимированная jQuery галерея.

Легкое слайд-шоу на jQuery c автоматической сменой слайдов.

37. Новая версия плагина «SlideDeck 1.2.2»

Профессиональный слайдер контента. Возможны варианты с автоматической сменой слайдо, а также вариант с использованием колеса мыши для перехода между слайдами.

38. jQuery слайдер «Sudo Slider»

Легкий сладер изображений на jQuery. Очень много вариантов реализации: горизонтальная и вертикальная смена изображений, со ссылками на номер слайда и без них, с подписями изображений и без, различные эффекты смены изображений. Есть функция автоматической смены слайдов. Ссылки на все примеры реализации можно найти на демонстрационной странице .

39. jQuery CSS3 слайд-шоу

Слайд-шоу с миниатюрами поддерживает режим автоматической смены слайдов.

40. jQuery cлайдер «Flux Slider»

Слайдер с множеством эффектов смены изображений.

41. Простой jQuery слайдер

Стильный слайдер изображений на jQuery.

То иногда приходится решать задачи, связанные с фронтэндом, несмотря на то, что я его недолюбливаю 🙂

О моём отношению к всему, что связано с «прекрасным» вы, собственно говоря, могли оценить по дизайну данного сайта, который разрабатывался мною единолично 🙂

Однако, сравнительно недавно я столкнулся с необходимостью реализации слайдера на JavaScript, причём сделать это нужно было без каких-либо готовых библиотек и даже без всеми любимого jQuery.

Вызвана данная необходимость была тем, что в результате должен был получиться JS скрипт, который через сторонний сервис подключался бы на сайт. Следовательно, готовые карусели на JavaScript сразу отпадали, т.к. для их интеграции нужно было в HTML код сайта добавлять подключение библиотеки через тэг script и копировать сами файлы либы на сервер или тянуть их по cdn, но для этого снова потребовалось бы править код ресурса.

Как сделать JavaScript слайдер: начало

Сегодня, думаю, что каждый, кто попадал в похожую ситуацию, начинал с поисков имеющихся наработок, т.к. когда задача сделать JS карусель стоит в рамках работы — это всегда должно быть сделано максимально быстро. И при таких условиях сидеть и выдумывать свои велосипеды, ясное дело, никто не позволит.

Заказчикам всегда наплевать на то, как код написан, какая у него архитектура, главное — видеть результат!

В итоге, как вы поняли, перед тем, как написать слайдер на JavaScript без jQuery, я решил подыскать готовый и доработать его под свои нужды. Почему без jQuery? Да потому что на целевом ресурсе, куда я планировал подключать свой слайдер через сервис, вызов jQuery в коде был расположен позже скрипта, подключаемого сервисом. Поэтому jQuery конструкции в моём коде просто не воспринимались.

В качестве основы я взял этот JavaScript слайдер изображений — https://codepen.io/gabrieleromanato/pen/pIfoD.

Остановиться я решил именно на нём, т.к. его JS код был написан с применением принципов ООП и классы в нём основываются на прототипах, а не на банальных функциях.

Честно говоря, я глубоко не понимаю и не признаю сегодняшнюю шумиху вокруг JavaScript с использование ООП, фреймворков и прочих архитектурных штук в языке, который изначально задумывался как простенький язык динамических сценариев. Равно как и сам JS я откровенно недолюбливаю с его синтаксическим винегретом, позволяющим одни и те же конструкции писать несколькими способами.

Но, к сожалению, в современном мире мои позиции мало кто разделяет, т.к. данный язык развивается сумасшедшими темпами и предпринимает даже попытки завоевать умы бэкенд разработчиков с помощью Node.js как альтернативы Java, PHP, C#, Ruby и других монстров.

В итоге, чтобы банально не остаться без работы, приходится по-тихоньку с JavaScript разбираться. А в выбранной мною реализации слайдера на чистом JavaScript я встретил то, что, как вы поняли, презираю в данном языке. Поэтому я её и выбрал, чтобы был хоть какой-то повод поработать и разобраться с JavaScript ООП и прототипными классами — иначе я бы к ним добровольно никогда в жизни не прикоснулся бы 🙂

На базе найденного мною кода мне необходимо было разработать слайдер на чистом JS во всплывающем окне (такую штуку ещё называют popup, попап и т.д.), который имел бы кнопки переключения слайдов и кликабельные индикаторы текущего слайда. Также нужно было сделать кнопку для закрытия данного окна.

Вот, что у меня получилось в итоге.

Делаем библиотеку JS слайдера

Сперва я решил всё реализовать по уму и сделать JavaScript слайдер для сайта в виде библиотеки, подключаемой на сайт одним-единственным скриптом, в котором будут вызываться компоненты слайдера, разбитые по подкаталогам. Назвать её я решил popupSlider.js в честь её изначального предназначения.

Её код можно найти на GitHub по этому адресу — https://github.com/Pashaster12/popupSlider.js

Структура библиотеки вышла следующая:

Папка slides предназначена для картинок слайдов. В controls размещены картинки элементов управления JS каруселью (кнопки закрытия слайдера и переключения слайдов). А в assets — статические элементы JS слайдера: HTML разметка и файл с CSS стилями.

Ну, а файл popupSlider.js — это и есть сердце самой библиотеки, в котором прописаны действия JavaScript карусели и устанавливается связь с остальными файлами. Именно его мы и будем подключать на сайте, а он уже будет вызывать остальные.

Я решил начать с HTML разметки нашей JS карусели картинок, которая в моём случае выглядит так:

Text 1 Text 2 Text 3

Для оформления слайдера на JavaScript в виде попапа я использовал следующие стили:

#slider { margin: auto; width: 600px !important; overflow: hidden; } #slider-wrapper { width: 9999px; height: 343px; position: relative; transition: left 400ms linear; } .slide { float: left; width: 600px; position: relative; overflow: hidden; } .caption { width: 600px; height: 110px; line-height: 1.5; font-size: 15px; font-weight: 300; text-align: center; color: #000; display:table; } .caption-container { display: table-cell; vertical-align: middle; padding: 0 20px; } #slider-nav { position: absolute; bottom: -36px; text-align: center; left: 50%; transform: translateX(-50%); } #slider-nav a { width: 8px; height: 8px; text-decoration: none; color: #000; display: inline-block; border-radius: 50%; margin: 0 5px; background-color: #fafafa; } #slider-nav a.current { background-color: #337ab7; } .horizontal-controls { position: absolute; display: inline-block; width: 12px; height: 20px; top: 50%; margin-top: -10px; } #prev { background: url(../controls/arrow_left_inactive.png); left: -40px; } #prev:hover { background: url(../controls/arrow_left_active.png); } #next { background: url(../controls/arrow_right_inactive.png); right: -40px; } #next:hover { background: url(../controls/arrow_right_active.png); } #cq-popup { width: 600px; z-index: 23; left: calc(50%); top: calc(50%); position: fixed !important; background-repeat: no-repeat; background-position: right; background-color: #fff; font-family: "Roboto","Segoe UI","Helvetica","Georgia","Calibri","Verdana"; transform: translate(-50%, -50%) scale(1); } #cq-popup .header { display: inline-block; font-size: 17px; font-weight: 500; } #cq-popup > div { width: 500px; font-size: 22px; line-height: 36px; } #cq-popup-btclose { text-decoration: none; position: absolute; right: -40px; top: 0; background: url(../controls/btn_delete_inactive.png); height: 16px; width: 16px; } #cq-popup-btclose:hover { background: url(../controls/btn_delete_active.png); } #cq-popup-bg { position: fixed; top:0; width: 100%; height: 100%; background: rgba(51,51,51,0.8); z-index: 22; }

В результате применения данных стилей JS карусель выглядит следующим образом:

И HTML разметку, и CSS стили я вынес в отдельные файлы popupSlider.html и popupSlider.css, которые расположены в директории assets библиотеки слайдера на JavaScript. Я сделал это специально, чтобы пользователи при использовании данного кода могли без проблем корректировать разметку и оформление, не лазя в JS коде, где вынесенное нужно было бы прописать напрямую.

Кроме того, многие ещё любят минимизировать JS для ускорения загрузки сайта. Так что кастомизировать данное решение при указанных условиях было бы очень сложно.

В итоге, я решил просто подключать готовые файлы в главном файле библиотеки popupSlider.js, который для моей постановки задачи принял следующий вид:

Function Slider(element) { this.loadStatic(); 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.nextBtn = this.el.querySelector("#next"); this.prevBtn = this.el.querySelector("#prev"); this.navigate(); }, navigate: function () { var self = this; for (var i = 0; i < this.links.length; ++i) { var link = this.links[i]; link.addEventListener("click", function (e) { self.slide(this); }); } self.prevBtn.style.display = "none"; self.nextBtn.addEventListener("click", function (e) { var currentSlideNumber = document.querySelector("#slider-nav a.current").getAttribute("data-slide"); var nextSlide = document.querySelector(""); nextSlide.click(); }, false); self.prevBtn.addEventListener("click", function (e) { var currentSlideNumber = document.querySelector("#slider-nav a.current").getAttribute("data-slide"); var prevSlide = document.querySelector(""); prevSlide.click(); }, false); self.close(); }, slide: function (element) { this.setCurrentLink(element); var index = parseInt(element.getAttribute("data-slide"), 10) + 1; var currentSlide = this.el.querySelector(".slide:nth-child(" + index + ")"); this.wrapper.style.left = "-" + currentSlide.offsetLeft + "px"; if (index < this.links.length) this.nextBtn.style.display = "block"; else if (index == this.links.length) this.nextBtn.style.display = "none"; if (index > 1) this.prevBtn.style.display = "block"; else if (index == 1) this.prevBtn.style.display = "none"; }, setCurrentLink: function (link) { var parent = link.parentNode; var a = parent.querySelectorAll("a"); link.className = "current"; this.currentElement = link; for (var j = 0; j < a.length; ++j) { var cur = a[j]; if (cur !== link) { cur.className = ""; } } }, loadStatic: function () { var self = this; var link = document.createElement("link"); link.rel = "stylesheet"; link.href = "assets/popupSlider.css"; document.head.appendChild(link); var sliderHTML = ""; var xhr = new XMLHttpRequest(); xhr.open("GET", "assets/popupSlider.html", false); xhr.send(); if (xhr.status != 200) { alert("Can not load the popupSlider.html. Got the error " + xhr.status + ": " + xhr.statusText); } else { sliderHTML = xhr.responseText; } var div = document.createElement("div"); div.innerHTML = sliderHTML; document.body.appendChild(div); }, close: function () { document.getElementById("cq-popup-btclose").onclick = function () { document.getElementById("cq-popup-bg").remove(); document.getElementById("cq-popup").remove(); } } };

Немного комментариев по поводу приведённого кода. Содержимое файла popupSlider.js является одним JavaScript классом Slider, который, как и в PHP, содержит конструктор и методы класса. Только в JS определение конструктора, в отличие от PHP, является обязательным.

Конструктор определяется с помощью следующей конструкции:

Function Slider(element) { //код конструктора }

Внутри конструктора должны быть прописаны действия, которые будут выполняться при создании объекта класса.

Сами методы класса будут находиться внутри прототипа и будут доступны для всех экземпляров данного JavaScript класса. JS прототип в моём случае описывается следующей конструкцией:

Slider.prototype = { //методы }

Вызываться за пределами тела класса они будут следующим образом:

Var slider = new Slider(); slider.class_method();

А внутри самого кода класса доступен следующий способ:

This.class_method();

Главное только не забывать, что в JavaScript значение this зависит от контекста вызова, поэтому в телах некоторых методов, в которых нужно было вызывать методы и свойства класса, присутствует такая конструкция:

Var self = this; self.class_method(); //чтобы обратиться к методу, находящемся на уровень выше кода описываемого метода

Вроде обо всех нюансах написания кода я рассказал. Теперь пару слов о методах нашего JavaScript класса, внутри которых содержатся описания действий JS карусели картинок.

loadStatic()

Самый первый метод, вызывающийся при создании экземпляра класса в конструкторе. Отвечает за добавление в HTML кода страницы сайта HTML разметки слайдера и файла со стилями.

Сначала в памяти создаётся новый тэг link с помощью JavaScript функции document.createElement() и ему присваиваются значения всех необходимых атрибутов, в том числе и путь к CSS файлу со стилями JS слайдера. И, в конце-концов, он добавляется в HTML страницы с помощью JavaScript метода appendChild() в конец секции head, где и должны стилей.

Далее мы делаем то же самое для файла с HTML разметкой нашего слайдера на чистом JavaScript. Вот только здесь есть маленький нюанс: просто так HTML файл внутри такого же подключить нельзя, как мы сделали это с CSS файлом. Для этого есть специальные библиотеки, например, для того, чтобы подключить HTML в HTML, отлично подходит либа от w3.org — https://www.w3schools.com/howto/howto_html_include.asp

Но тогда её пришлось бы или подключать в саму библиотеку слайдера, или просить о самостоятельной её установке пользователей. Но всё это неоптимально, т.к. требует много телодвижений и замедляет скорость загрузки сайта за счёт дополнительных скриптов.

В итоге, я решил получать содержимое HTML файла внутри JavaScript кода и загружать его в новый div элемент, создаваемый в памяти, как я делал это ранее для подключения CSS файла в JavaScript. Сгенерированный элемент подключается в самый конец секции body HTML кода страницы сайта.

Если хотите вставить div с разметкой слайдера не просто в конец body, а в какой-то конкретный контейнер, то можете вместо следующего кода:

Var div = document.createElement("div"); div.innerHTML = sliderHTML; document.body.appendChild(div);

Прописать следующее, указав нужный идентификатор целевого контейнера (в моём случае HTML JS слайдера будет расположен в элементе с id popupSlider):

Var target = document.querySelector("#popupSlider"); target.innerHTML = sliderHTML;

Метод, который вызывается в конструкторе после loadStatic(), и нужен для инициализации свойств класса, соответствующих основным HTML элементам, к которым мы будем обращаться в следующем коде.

В конце вызывается метод navigate().

navigate()
В данном методе происходит указание действий, происходящих при клике на кнопки переключения слайдов и элементы навигации, расположенные под самим слайдером, в виде кружочков.

Сам JavaScript код смены слайдов для удобства я вынес в отдельный метод slide(), а в данном я только навешиваю его на событие click для каждой круглой кнопки в цикле.

При клике на кнопки «предыдущий слайд»/»следующий слайд» я, как видите, решил всего лишь эмулировать нажатие на соответствующий кружочек, определяя нужный относительно текущего, у которого имеется CSS класс current.

slide(element)

Метод, «отвечающий за магию» самой JavaScript карусели, в котором содержится код, меняющий слайды местами. В самом начале вызывается метод setCurrentLink(), о котором мы поговорим чуточку позже.

В качестве входного параметра в него передаётся объект кнопки навигации JS слайдера в виде кружочка.

Само переключение слайдов работает следующим образом:

  • Все слайды у нас оформлены в виде блоков одинаковых размеров, идущих друг за другом. Окно слайдера — это лишь видимая часть элемента, содержащего все слайды.
  • Мы определяем смещение левого края текущего слайда от левого края родительского элемента с помощью свойства offsetLeft.
  • И сдвигаем родительский элемент на это значение, чтобы в окне слайдера у нас отображался необходимый элемент.
  • В конце метода описано поведение для кнопок «предыдущий слайд»/»следующий слайд», оформленных в виде стрелок влево/вправо соответственно. Если текущий слайд — первый из всего списка, то кнопка перехода к предыдущему слайду скрывается. Если последний, то убираем кнопку перехода к следующему слайду.

    setCurrentLink(link)

    Данный метод нашего класса JavaScript слайдера отвечает за подсветку навигационной круглой кнопки, соответствующей текущему элементу. Т.е. если у нас выбран второй слайд, то будет подсвечиваться вторая кнопочка.

    В качестве входного параметра в функцию передаётся объект кнопки, которая должна быть выделена как текущая.

    Логика выделения текущего элемента проста:

  • Получаем объект родительского элемента, которым в нашем случае выступает контейнер с идентификатором slider-nav .
  • Получаем все навигационные элементы в виде массива ссылок.
  • Выделяем элемент, полученный на входе, путём добавления ему классу current .
  • В цикле перебираем все навигационные элементы и у всех, кроме текущего, очищаем значение класса. Это нужно для того, чтобы снять выделение с элемента, которым был текущим до данного вызова функции.
  • Самый последний метод класса, в котором определяется действие при нажатии на кнопку закрытия слайдера в виде крестика. Здесь, собственно говоря, код самый понятный из всего, содержащегося в классе JS слайдера.

    При нажатии на кнопку закрытия, доступ к которой получается по её идентификатору, происходит удаление со страницы элемента слайдера и элемента, задающего полупрозрачный фон. Они также, в свою очередь, получаются по уникальным идентификаторам.

    Сам метод вызывается внутри описанного ранее navigate(), который содержит в себе все сценарии действий, происходящих на нашем JavaScript слайдере.

    Кстати, если вы захотите сделать закрытие слайдера при клике за его пределами, то достаточно в данный метод добавить следующий код:

    Document.getElementById("cq-popup-bg").onclick = function () { document.getElementById("cq-popup-bg").remove(); document.getElementById("cq-popup").remove();

    JavaScript слайд шоу на базе разработанной библиотеки

    Иногда на практике может потребоваться сделать JS карусель с прокруткой, которую часто называют слайд шоу. В моём случае этого не требовалось, но я всё же решил сделать такую на базе итогового кода библиотеки для случая, когда это может пригодиться.

    На самом деле, реализация JavaScript слайд шоу отличается от обычного слайдера совсем незначительно. Разница заключается лишь в том, что в слайд шоу слайды переключаются автоматически с заданным временным интервалом, а в случае обычной JS карусели они меняются вручную с помощь элементов навигации.

    SlideShow: function (timeout) { var sliderCount = this.links.length; var self = this; this.slideCycle = setInterval(function () { var currentSlideNumber = document.querySelector("#slider-nav a.current").getAttribute("data-slide"); var slideId = parseInt(currentSlideNumber, 10) + 1; self.slide(document.querySelector("")); }, timeout); }

    Что здесь происходит — думаю, понятно. Для создания данного метода я скопировал код из события клика на кнопки ручного переключения слайдов и разместил его внутри вызова JavaScript функции setInterval(), которая выполняет указанное действие через заданный промежуток времени.

    Сценарий действия передаётся первым аргументом в виде анонимной функции, а временной интервал — вторым, который я решил сделать в виде переменной, значение которой передаётся при вызове slideShow().

    Единственная модификация кода внутри setInterval(), которая потребовалась, — это определение количества слайдов и сравнение с ним индекса текущего слайда для зацикленности автоматического переключения.

    Ну, и для того, чтобы данный код заработал, сам метод необходимо вызвать. Я решил сделать это всё в том же navigate(), который как раз и является сборником всяких сценариев. Вызов я разместил в самом конце, передав в качестве аргумента значение временного интервала для автоматической смены слайдов в нашем JS слайд шоу (я выбрал 2000 милисекунд или 2 секунды, вы можете по необходимости изменять это число):

    self.slideShow(2000);

    После этого проверяйте работу JavaScript слайдера, не забыв при этом почистить и браузера.

    По идее, всё должно работать. Если нет — изучайте ошибки в консоли браузера и делитесь ими в комментариях.

    В итоге, у нас получилось JS слайд шоу, в котором слайды переключаются автоматически и по кругу, т.е. при достижении последнего слайда шоу переходит на новый цикл, и показ снова начинается с самого первого элемента.

    При работе с различными библиотеками JS каруселей картинок и отзывов я заметил, что данную практику разработчики активно применяют, но с некоторым дополнением. Во всех увиденных мною решениях автоматический показ слайдов прерывается, если пользователь сделал ручное переключение. Поэтому я решил сделать подобное и в своей библиотеке.

    Для прерывания автоматического показа слайдов JavaScript карусели я решил воспользоваться стандартной JS функцией clearInterval(), которой в качестве аргумента передаю идентификатор временного интервала, возвращаемого функцией setInterval() при его установке.

    В итоге, получился следующий код, который я решил не оформлять отдельным методом:

    ClearInterval(self.slideCycle);

    И разместил его в местах описания действий при кликах на различные элементы навигации, т.е. в следующих:

    Link.addEventListener("click", function (e) {...}); self.prevBtn.addEventListener("click", function (e) {...}); self.nextBtn.addEventListener("click", function (e) {...});

    Вызов clearInterval() лучше делать поближе к самому событию клика, главное, чтобы перед ним, а не после.

    Интеграция JavaScript слайдера на сайт

    Итак, наш слайдер на чистом JS готов. Осталось теперь только подключить его на сайт.

    Для этого необходимо выполнить последовательно следующие шаги, которые являются стандартными действиями при интеграции каких-либо сторонних JavaScript библиотек вообще.

    Шаг 1 . Копируем файлы библиотеки к себе на сайт в отдельный каталог.
    Шаг 2 . Добавляем следующий код в HTML страниц, на которых необходимо будет отображение слайдера, разместив его перед закрывающимся тэгом body:

    Шаг 3 . Размещаем следующий код вызова JS карусели в каком-либо существующем JavaScript файле, который подключается на странице после подключения самого слайдера:

    Var aSlider = new Slider("#slider");

    Как видите, данный код, — это, по сути, создание объекта класса Slider, который содержится в popupSlider.js. Именно поэтому его вызов должен быть только после подключения самого файла класса на страницу.

    Добавление новых слайдов в JavaScript карусель

    Здесь всё очень просто. Поскольку слайды у нас берутся из отдельной директории библиотеки slides , то при добавлении новых картинок нужно будет просто закинуть в неё нужные файлы, задав им предварительно такой же размер, как и у других.

    А затем в коде файла assets/popupSlider.html добавить новый блок в контейнер с id slider-wrapper :

    Text

    В принципе, можете просто скопировать аналогичный существующий и изменить в нём путь к файлу изображения и текст подписи (если она вообще будет нужна).

    Также необходимо будет добавить новый элемент навигации в виде кружочка, т.к. на данный момент автоматическое его добавление пока не реализовано. Для этого нужно будет добавить следующий код в контейнер с id slider-nav , прописав его в самом конце:

    Значение атрибута data-slide должно быть больше самого большого у остальных элементов. Достаточно всего лишь увеличить максимальное текущее на единицу.

    Упаковка JS карусели в единый скрипт

    Всё, слайдер на JavaScript готов и подключен. Я лично рекомендую использовать данный вариант на практике, если он вам вообще пригодится 🙂

    Для ускорения работы его, кстати, можете ещё дополнительно сжать статические компоненты: CSS, HTML и JavaScript файлы. Я не стал этого делать и предлагать вам минифицированный код, потому что систем сборок фронтэнда сейчас очень много: Gulp, Grunt, Webpack и другие. И у каждой из них свои алгоритмы сжатия и подключения файлов.

    К тому же, минифицированные результаты на разных ОС могут работать по-разному. В общем, причин много.

    Да и сами исходники у меня вышли, я считаю, не такие уж тяжеловесные, что нуждаются в данной процедуре. Но если же вам они будут необходимы, то настройте минификацию самостоятельно с учётом вашей ОС и сборщика.

    Как я писал в самом начале, для решения поставленной мне изначально задачи нужно было получить единый JS файл для корректного использования моего слайдера через сторонний сервис на сайте. По этой причине я, собственно говоря, и не стал пользоваться готовыми сторонними библиотеками.

    Тогда вариант единого скрипта JavaScript карусели вам придётся как нельзя кстати, т.к. весь контент будет содержаться прямо в нём, в том числе и HTML/CSS код, который в случае библиотеки хранится в отдельных файлах.

    Скрипт в моём случае состоит из двух частей. В первой части располагалось содержимое файла popupSlider.js, которое я второй раз не буду приводить. Вставьте его самостоятельно, убрав из кода класса описание метода loadStatic() и его вызов, т.к. они нам не понадобятся.

    Вторая же часть единого скрипта JavaScript слайдера для сайта представляет собой обработчик события DOMContentLoaded, которое наступает при загрузке содержимого страницы.

    Там у нас будет происходить добавление на страницу HTML/CSS кода JS карусели и создание объекта класса Slider, что равносильно активации самого слайдера.

    Схематично код выглядит следующим образом:

    /* содержимое popupSlider.js без описания метода loadStatic() и его вызова */ document.addEventListener("DOMContentLoaded", function(){ var str = "\ \ /*css код*/ \ /* html код */ "; var div = document.createElement("div"); div.innerHTML = str; document.body.appendChild(div); var aSlider = new Slider("#slider");

    Поскольку в моём случае вариант загрузки файлов на сервер был вообще закрыт, мне пришлось загрузить файлы картинок элементов управления JavaScript каруселью на облако и вместо путей к ним в HTML и CSS коде прописать ссылки, сгенерированные при сохранении.

    Если у вас таких сложностей нет, то можете ничего не менять, но не забыть скопировать каталоги slides и controls библиотеки на сервер и указать правильные пути к ним.

    Самописный JS слайдер — перспективы развития

    Честно скажу, что заниматься целенаправленной поддержкой и развитием созданного мною решения я заниматься не планирую 🙂 На данный момент подобных слайдеров существует вагон и маленькая тележка, которые, в отличие от моего имеют свою историю, тщательно оттестированы и поддерживаются обширным комьюнити пользователей и разработчиков.

    Мне же начинать весь этот путь с нуля в одиночку и создавать ещё один велосипед как-то не интересно, да и времени на это толком нет. Но, зато данный JavaScript слайдер является отличной возможностью попрактиковаться в разработке путём рефакторинга его кода и реализации новых интересных функций, которых, возможно, на данный момент ещё нет.

    Так что если вам, как и мне, нужна будет кодовая база для экспериментов и вы располагаете хоть каким-то лишним свободным временем — копируйте себе код описанного мною JavaScript слайдера или присоединяйтесь к контрибьюторам на GitHub. Репозиторий открытый, а ссылку на него я предоставил в начале статьи.

    Если вы хотите прокачать свои фронтэнд скилы на моём творении, могу вам даже подкинуть небольшой список правок и доработок, в которых нуждается код и которые, возможно, будут интересны вам в плане их реализации:

  • сделать внешний конфиг, чтобы можно было удобно настраивать слайдер;
  • сделать возможность встраивания слайдера внутрь страницы (сейчас оформлен только в виде попапа);
  • асинхронная загрузка HTML кода (сейчас сделана синхронная, которая многими браузерами помечается как устаревший вариант);
  • оформить библиотеку в виде пакета, NPM, Bower или другого пакета, чтобы его можно было устанавливать и оперировать зависимостями с помощью пакетных менеджеров;
  • сделать вёрстку адаптивной для использования JS карусели на различных устройствах;
  • сделать переключение слайдов по событию Swipe для мобильных пользователей.
  • Приведённый мною список правок, естественно, не конечный и может быть дополнен. Пишите о своих предложениях, мыслях и пожеланиях в комментариях под статьёй и делитесь со своими друзьями через социальные сети, чтобы их также привлечь к разработке.

    Прошу мой код строго не судить, т.к., я как я уже говорил, Frontend спецом я себя не считаю и не являюсь. Также я открыт для всех ваших замечаний по стилю кодирования и надеюсь, что смогу что-то у вас перенять, а вы — у меня, т.е. выполнить основное предназначение разработки и поддержки OpenSource продукции.

    Вступайте в сообщества проекта, подписывайтесь на обновления и можете даже помочь мне материально с помощью формы прямо под самой статьёй, если я чем-то смог вам помочь или вам просто нравится то, чем я занимаюсь 🙂

    У меня всё! Всем добра! 🙂

    P.S. : если вам нужен сайт либо необходимо внести правки на существующий, но для этого нет времени и желания, могу предложить свои услуги.

    Более 5 лет опыта профессиональной разработки сайтов. Работа с PHP , OpenCart , WordPress , Laravel , Yii , MySQL , PostgreSQL , JavaScript , React , Angular и другими технологиями web-разработки.

    Опыт разработки проектов различного уровня: лендинги , корпоративные сайты , Интернет-магазины , CRM , порталы . В том числе поддержка и разработка HighLoad проектов . Присылайте ваши заявки на email [email protected] .

    Статьи по теме: