Часто по работе приходится встраивать в страницу слайдеры прокрутки изображений, блоков и т.д. Наигравшись с «чужими» разработками, которые часто обладают лишним и ненужным мне функционалом было решено сделать свой велосипед и оформить его в виде плагина для jQuery, который бы банально выполнял свои функцию горизонтального слайдера, и был бы мне понятен От и До.
Данная реализация далеко не претендует на идеальную, так как это мой первый плагин, да и код может быть через время мне будет видеться страшным, но сейчас мне кажется все прекрасно и довольно радужно и может быть кому-то будет полезным.
Сначала нужно изучить правила оформления плагина для jQuery. Я пользовался информацией по этой ссылке. Откуда я узнал, что для файлов с плагинами jQuery существует соглашение касательно их названия — оно должно удовлетворять формату jquery.pluginName.js. Таким образом, файл с нашим плагином нужно будет назвать jquery.lbslider.js — именно так я решил назвать свой слайдер, почему lb не понятно никому, кроме моей любимой невесты (нужно же, чтобы была хоть какая-то загадка). Сам же код плагина должен иметь такое оформление (более подробно можно почитать по ссылке выше):
(function($){
jQuery.fn.pluginName = function(options){
// Зададим список свойств и укажем для них значения по умолчанию.
// Если при вызове метода будут указаны пользовательские
// варианты некоторых из них, то они автоматически перепишут
// соответствующие значения по умолчанию
options = $.extend({
param1: 'param1Value', //параметр1
param2: 'param2Value' //параметр2
}, options};
var make = function(){
// реализация работы метода с отдельным элементом страницы
};
return this.each(make);
// в итоге, метод pluginName вернет текущий объект jQuery обратно
};
})(jQuery);
Для начала я решил использовать такие параметры в своей реализации:
leftBtn — кнопка для прокрутки слайдера влево
rightBtn — кнопка для прокрутки слайдера влево
quantity — количество видимых элементов на странице (иногда их нужен всего 1, а иногда и 3, 4 и более)
autoPlay — булевое значение, указывающее, нужна ли автопрокрутка слайдера
autoPlayDelay — задержка при автопрокрутке
Итак, вот мои опции по умолчанию:
var options = $.extend({
leftBtn: 'leftBtn',
rightBtn: 'rightBtn',
quantity: 4,
autoPlay: false, // true or false
autoPlayDelay: 10 // delay in seconds
}, options);
Теперь приступим непосредственно к реализации. Я решил что html код слайдера будет состоять из блока-обертки, внутри которого будут находится кнопки для прокрутки и еще один блок со списком <ul>, элементы которого и будут проркучиваться. Сначала добавим несколько стилей.
var make = function() {
$(this).css('overflow', 'hidden');
var el = $(this).children('ul');
el.css({
position: 'relative',
left: '0'
});
};
Прокрутку решено было сделать бесконечной, для этого продублируем несколько элементов с конца вначале и несколько первых элементов в конце. Несколько — это как раз количество наших видимых элементов на странице — параметр quantity.
var sliderFirst = el.children('li').slice(0, options.quantity);
var tmp = '';
sliderFirst.each(function(){
tmp = tmp + '<li>' + $(this).html() + '</li>';
});
sliderFirst = tmp;
var sliderLast = el.children('li').slice(-options.quantity);
tmp = '';
sliderLast.each(function(){
tmp = tmp + '<li>' + $(this).html() + '</li>';
});
sliderLast = tmp;
var elRealQuant = el.children('li').length;
el.append(sliderFirst);
el.prepend(sliderLast);
Если Вы заметили, мы также сохранили первоначальное количество элементов в переменной elRealQuant — оно нам еще пригодится. Далее установим ширину одного элемента, она зависит от ширины всего блока и от количества видимых элементов, также установим CSS свойство float: left. Узнаем новое количество всех элементов, после того, как мы продублировали некоторые из них и установим ширину всего списка равной количеству элементов умноженному на ширину одного элемента.
var elWidth = el.width()/options.quantity;
el.children('li').css({
float: 'left',
width: elWidth
});
var elQuant = el.children('li').length;
el.width(elWidth * elQuant);
el.css('left', '-' + elWidth * options.quantity + 'px');
Мы также сдвинули весь список влево, чтобы добавленные в начало дублированные элементы были не видны при загрузке страницы.
Теперь добавим функции отключения кнопок прокрутки на время самой анимации прокручивания и последующего их включения. Это будет просто элементарное добавление/убирание класса inactive к кнопкам, а по нажатии на кнопки будем проверять, если этот класс есть — ничего не делать. Конечно также можно задать отдельное стилевое оформление для таких кнопок.
function disableButtons() {
$('.' + options.leftBtn + ', .' + options.rightBtn).addClass('inactive');
}
function enableButtons() {
$('.' + options.leftBtn + ', .' + options.rightBtn).removeClass('inactive');
}
Теперь напишем собственно функции, которые будут отрабатывать по нажатии кнопок прокрутки слайдера:
$('.' + options.leftBtn).click(function(event){
event.preventDefault();
if (!$(this).hasClass('inactive')) {
disableButtons();
el.animate({left: '+=' + elWidth + 'px'}, 300,
function(){
if ($(this).css('left') == '0px') {$(this).css('left', '-' + elWidth * elRealQuant + 'px');}
enableButtons();
}
);
}
return false;
});
Это функция для левой кнопки. Сначала мы отключаем кнопки, затем соответственно проводим саму анимацию прокрутки и потом снова делаем активными кнопки. По окончании анимации проверяем, если слайдер дошел до левого края — перемещаем весь блок снова на нужное количество вправо — пользователь на экране не увидит этого и снова можно будет листать влево — и так до бесконечности. Функция для правой кнопки будет аналогичной, только прокручивать будем в другую сторону и проверять будем, если прокрутили до правого края — сдвигать влево.
Осталось только сделать автопрокрутку, если таковая задана. Вобщем это будет просто периодическая эмуляция нажатия на одну из кнопок. Также при наведении на слайдер прокрутка будет останавливаться, а при убирании курсора — возобновляться.
if (options.autoPlay) {
function aPlay() {
$('.' + options.rightBtn).click();
delId = setTimeout(aPlay, options.autoPlayDelay * 1000);
}
var delId = setTimeout(aPlay, options.autoPlayDelay * 1000);
el.hover(
function() {
clearTimeout(delId);
},
function() {
delId = setTimeout(aPlay, options.autoPlayDelay * 1000);
}
);
}
Ну вот собственно и все. Можно посмотреть теперь весь код плагина.
(function($){
$.fn.lbSlider = function(options) {
var options = $.extend({
leftBtn: 'leftBtn',
rightBtn: 'rightBtn',
quantity: 3,
autoPlay: false, // true or false
autoPlayDelay: 10 // delay in seconds
}, options);
var make = function() {
$(this).css('overflow', 'hidden');
var el = $(this).children('ul');
el.css({
position: 'relative',
left: '0'
});
var sliderFirst = el.children('li').slice(0, options.quantity);
var tmp = '';
sliderFirst.each(function(){
tmp = tmp + '<li>' + $(this).html() + '</li>';
});
sliderFirst = tmp;
var sliderLast = el.children('li').slice(-options.quantity);
tmp = '';
sliderLast.each(function(){
tmp = tmp + '<li>' + $(this).html() + '</li>';
});
sliderLast = tmp;
var elRealQuant = el.children('li').length;
el.append(sliderFirst);
el.prepend(sliderLast);
var elWidth = el.width()/options.quantity;
el.children('li').css({
float: 'left',
width: elWidth
});
var elQuant = el.children('li').length;
el.width(elWidth * elQuant);
el.css('left', '-' + elWidth * options.quantity + 'px');
function disableButtons() {$('.' + options.leftBtn + ', .' + options.rightBtn).addClass('inactive');}
function enableButtons() {$('.' + options.leftBtn + ', .' + options.rightBtn).removeClass('inactive');}
$('.' + options.leftBtn).click(function(event){
event.preventDefault();
if (!$(this).hasClass('inactive')) {
disableButtons();
el.animate({left: '+=' + elWidth + 'px'}, 300,
function(){
if ($(this).css('left') == '0px') {$(this).css('left', '-' + elWidth * elRealQuant + 'px');}
enableButtons();
}
);
}
return false;
});
$('.' + options.rightBtn).click(function(event){
event.preventDefault();
if (!$(this).hasClass('inactive')) {
disableButtons();
el.animate({left: '-=' + elWidth + 'px'}, 300,
function(){
if ($(this).css('left') == '-' + (elWidth * (options.quantity + elRealQuant)) + 'px') {$(this).css('left', '-' + elWidth * options.quantity + 'px');}
enableButtons();
}
);
}
return false;
});
if (options.autoPlay) {
function aPlay() {
$('.' + options.rightBtn).click();
delId = setTimeout(aPlay, options.autoPlayDelay * 1000);
}
var delId = setTimeout(aPlay, options.autoPlayDelay * 1000);
el.hover(
function() {
clearTimeout(delId);
},
function() {
delId = setTimeout(aPlay, options.autoPlayDelay * 1000);
}
);
}
};
return this.each(make);
};
})(jQuery);
И вызывается он довольно просто. Примерно вот так:
$('.slider').lbSlider({leftBtn: 'sa-left', rightBtn: 'sa-right', quantity: 3, autoPlay: true});
И конечно ДЕМО
Не обошлось и без недочетов. Например ширину оберточного блока лучше задавать вручную и так, чтоб она делилась нацело на количество видимых элементов, иначе с дробными значениями возникают баги, дойдя до краев.
Конечно можно еще расширять функционал — например добавить некоторые эффекты при самой прокрутке, добавить возможность вертикальной прокрутки, и конечно убрать недочеты, но на сегодня довольно.
Автор: equinox7