Слайдер с прокруткой (карусель)
Как всегда, начнем с постановки задачи: на сей раз нам потребуется создать слайдер, который будет прокручивать изображения используя эффект сдвига. Естественно, у него должны присутствовать кнопки навигации и анимация должна останавливаться, если курсор мыши находится в области карусели.
Для кнопок навигации будем использовать то же изображение, что и в предыдущем примере:
html разметку в этот раз немного усложним - будем прокручивать не просто картинки, а блоки в которых помимо изображений присутствует текст. Ну и еще одно изменение коснется кнопок прокрутки. Их мы тоже добавим непосредственно в разметку, а не с помощью js, как это делали в предыдущем примере. Вот что получится в итоге:
<div class="carousel_wrap">
<span class="prev">prev</span>
<span class="next">next</span>
<div class="visual_block">
<ul>
<li>
<img src="/slider_image1.jpg" alt="" />
<div class="text">Подпись к фото 1</div>
</li>
<li>
<img src="/slider_image2.jpg" alt="" />
<div class="text">Подпись к фото 2</div>
</li>
<li>
<img src="/slider_image3.jpg" alt="" />
<div class="text">Подпись к фото 3</div>
</li>
</ul>
</div>
</div>
Всю конструкцию мы помещаем в общий контейнер с классом carousel_wrap. Кнопки оформляем с помощью элементов span. Контейнер с классом visual_block будет служить окном, в котором будет отображаться содержимое слайда, а сами слайды (оформим их в виде ненумерованного списка) должны будут располагаться друг за другом. Само собой, ограничений на количество элементов LI нет.
Оформим внешний вид с помощью css:
.carousel_wrap {
margin: 50px auto;
width:700px;
position:relative;
}
.visual_block {
margin: 0 auto;
position: relative;
overflow: hidden;
}
.visual_block ul {
position: relative;
}
.visual_block ul, .visual_block li {
float: left;
}
.carousel_wrap span.next, .carousel_wrap span.prev {
margin-top:-20px;
width:15px;
height:26px;
display:block;
text-indent:-9999px;
overflow:hidden;
cursor:pointer;
background:url(slider2_arrow.png) no-repeat;
position:absolute;
top:50%;
}
.carousel_wrap span.next {
right:0;
background-position:-15px 0;
}
.carousel_wrap span.next:hover {
background-position:-15px -26px;
}
.carousel_wrap span.prev:hover {
background-position:0 -26px;
}
Можно приступать к написаню js кода. Подумаем, как это можно сделать.
Сейчас все элементы LI расположены друг под другом. Что бы осуществить задуманное, нам потребуется выстроить их в один ряд, установить ширину блока visual_block равной ширине одного слайда (тогда отображаться будет только один элемент - все остальные обрежутся) и заставить слайды сдвигаться на эту же ширину через определенные промежутки времени. Удобнее всего будет, если размеры всех блоков будут высчитываться динамически. В jQuery подобное реализуется несколькими способами. Для нашего случая воспользуемся методами outerWidth() и outerHeight(). Эти методы вернут размеры отобранного элемента со всеми отступами. Ну и конечно, что бы было удобно оперировать значениями, будем сохранять их в переменных. Приступим.
Сначала объявим переменные для блоков оберток.
var elWrap = $('div.carousel_wrap'),
visual = $('div.visual_block')
carousel = visual.children('ul');
Далее добавим переменные visible (в ней будем хранить количество отображаемых блоков - в нашем случае это 1), itemWidth, itemHeight и itemsTotal (сюда положим значения ширины и высоты одного слайда, а так же их общее количество).
var elWrap = $('.carousel_wrap'),
visual = $('.visual_block'),
carousel = visual.children('ul'),
visible = 1,
itemWidth = carousel.children().outerWidth(),
itemHeight = carousel.children().outerHeight(),
itemsTotal = carousel.children().length;
Теперь мы спокойно можем вычислить необходимые размеры контейнеров visual_block, visual_block ul и присвоить им нужные значения:
visual.css({'width': visible * itemWidth + 'px', 'height' : itemHeight});
carousel.css({'width': itemsTotal * itemWidth, 'left': 0});
Конструкция приобрела необходимый вид, но все еще не работает. Нужно заставить слайды двигаться (предположим, влево). Сделаем это, воспользовавшись методом animate, который будет смещать элемент UL влево.
carousel.animate({left: -itemWidth}, 500);
Тут мы применили метод animate к блоку UL и в параметрах указали, что блок нужно сдвинуть относительно левого края visual_block на расстояние, равное значению переменной itemWidth за промежуток времени 500 мл с. Что бы блок уехал в нужном направлении, переменной itemWidth задали отрицательное значение. К сожалению, такой записью желаемого результата добиться не удалось. Все, чего мы достигли, это смещение UL относительно visual_block всего один раз. Не беда, мы уже проделывали трюки с многократным повторением одного и того же действия (вспоминаем прошлый пример). Поступим так же и в этот раз. Создадим функцию, в которую "упакуем" нашу запись и будем вызывать ее с помощью метода setInterval, скажем, каждые три секунды.
function chengeLeft () {
carousel.animate({left: -itemWidth}, 500);
}
setInterval(chengeLeft, 3000);
Снова неудача - смещение UL по прежнему происходит один раз. Оно и понятно. Мы же указали, что элемент требуется сдвинуть на itemWidth, задача выполнена и больше ничего не происходит. Последующие вызовы функции срабатывают в холостую. А что, если заставить UL возвращаться назад? Тогда каждый раз, когда будет вызываться функция элемент будет находиться в своем начальном положении. Попробуем. Возвращать элемент обратно нам нужно после того, как отработает animate. Вот и зададим ему в качестве третьего параметра так называемую callBack функцию, которая вернет UL в первоначальное положение.
function chengeLeft () {
carousel.animate({left: -itemWidth}, 500, function() {
carousel.css({"left": 0 });
});
}
setInterval(chengeLeft, 3000);
Посмотрим на результат. На первый взгляд может показаться, что снова ничего хорошего не вышло. Каждые три секунды первый слайд сдвигается влево, уступая место второму и тут же возвращается назад... Полный провал.
На самом деле это не так. Нам просто нужно сделать еще несколько действий в callBack функции, а именно, клонировать первый элемент (который спрятался) и поместить клон в самый конец карусели, затем удалить этот элемент в начале карусели и только после этого вернуть UL на место. Осуществим задуманное.
function chengeLeft () {
var item = carousel.children().eq(0);
carousel.animate({left: -itemWidth}, 500, function() {
item.clone().appendTo(carousel);
item.remove();
carousel.css({"left": 0 });
});
}
setInterval(chengeLeft, 3000);
В функции chengeLeft объявляем переменную item, в которой будем хранить первый слайд. Затем в callBack функции клонируем слайд, перемещаем клон в конец карусели и удаляем сам элемент. В итоге нас ожидает полный успех. Мы запустили автоматическую прокрутку. Весь код теперь выглядит так:
$(document).ready(function(){
var elWrap = $('.carousel_wrap'),
visual = $('.visual_block'),
carousel = visual.children('ul'),
visible = 1,
itemWidth = carousel.children().outerWidth(),
itemHeight = carousel.children().outerHeight(),
itemsTotal = carousel.children().length;
visual.css({'width': visible * itemWidth + 'px', 'height' : itemHeight});
carousel.css({'width': itemsTotal * itemWidth, 'left': 0});
function chengeLeft () {
var item = carousel.children().eq(0);
carousel.animate({left: -itemWidth}, 500, function() {
item.clone().appendTo(carousel);
item.remove();
carousel.css({"left": 0 });
});
}
setInterval(chengeLeft, 3000);
});
Скачать готовый код примера можно по ссылке ниже:
В следующей статье мы закончим работу над слайдером - каруселью, заставив работать кнопки навигации.