Галерея в виде обложек при помощи jQuery
В приложении iTunes можно заметить интересный эффект под названием CoverFlow. В данном уроке мы рассмотрим как сделать такую удобную навигацию с помощью jquery и css. Данная навигация станет отличным инструментом для навигации по большим коллекциям изображений или фонотеке музыки. Одним из преимуществ является трансформации css, которые придают эффект трехмерности изображений. Данный эффект обычно создают с помощью flash, но это не совсем практично и удобно в использовании, все это можно сделать достаточно проще..
..с помощью библиотек виджетов jquery ui. Фабрика виджетов является очень полезным инструментом, так как она предлагает последовательные, хорошо определенные структуры для создания и взаимодействия с плагинами с фиксацией состояния. Совсем не обязательно использовать фабрику виджетов, но она упрощает процесс установки стандартной конфигурации. При использовании фабрики виджетов надо помнить, что конечный результат не является виджетом jQuery UI – это все еще плагин jQuery, но с API похожей на jQuery UI.
Кодируем эффект CoverFlow с помощью фабрики виджетов jQuery UI $.widget.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
$.widget('namespace.nameOfPlugin', { // Опции по умолчанию options: { value: 10, display: false }, _create: function(){ // Вызывается при инициализации плагина // this.options является комбинацией опций по умолчанию с переданными установками // Пример использования this.options if (this.options.display) { // Проверка параметров дисплея } }, _someprivatemethod: function(value) { // Частная внутренняя функция // Примечание: частные функции должны именоваться с первым символом подчеркивания, // так как их возможно вызвать только внутри плагина // Функция возвращает переданное значение, увеличенное на 100. return value + 100; }, somepublicmethod: function() { // Публичная функция, которая может быть вызвана вне плагина. // Вызов частного метода в публичном. this._privatemethod(); }, value: function(value) { // Данная функция работает на выдачу значения, // то есть она возвращает значение опции, а не объект jQuery // Значение не передано, выдаем текущее значение if (value === undefined) { return this.options.value; // Значение передано, устанавливаем новое значение для опции } else { this.options.value = this._someprivatemethod(value); } }, destory: function() { $.widget.prototype.apply(this, arguments); // Деструктор по умолчанию //Здесь можно выполнить операции отката для страницы } })); |
Примечание: следующие методы по умолчанию доступны в каждой реализации плагина $.widget plugin:
- destroy(): удаляет экземпляр из DOM
- option(название_опции[, значение]): получает или устанавливает значения опций для данного экземпляра
- enable(): разрешает использование функционала виджета, если она ранее было запрещена методом disable
- disable(): запрещает использование функционала виджета
И следующее свойство доступно по умолчанию:
- options: опции экземпляра виджета, смешение значений по умолчанию с установками обеспечивается пользователем
Используя выше описанную структуру можно инициализировать только что созданный плагин:
1 |
$('#myelement').nameOfPlugin(); |
Также можно вызвать публичные методы:
1 2 3 4 5 6 7 |
$('#myelement').nameOfPlugin('somepublicmethod'); // Инициализация плагина со значениями по умолчанию $('#myelement').nameOfPlugin({ value: 70 }; // Получаем текущее значение опции alert($('#myelement').nameOfPlugin('value'); // Устанавливаем текущее значение опции $('#myelement').nameOfPlugin(', 45); |
Создание плагина jQuery со статическим состоянием не занимает много времени, а $.widget
обеспечивает удобный способ для написания виджетов.
Для генерирования эффекта CoverFlow используется несколько функций, но ключевыми являются select()
и _refresh()
. Функция select()
выполняет анимацию перемещения при выборе обложки, а функция _refresh()
генерирует информацию для трансформации обложки при различных действиях, таких как инициализация CoverFlow или нажатие на обложке для переноса ее на основной вид.
ui.coverflow.js.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
select: function(item, noPropagation) { this.previous = this.current; this.current = !isNaN(parseInt(item,10)) ? parseInt(item,10) : this.items.index(item); // Если нажатие произошло на том же пункте, то анимацию не выполняем if(this.previous == this.current) return false; // Изменяем $.fx.step.coverflow каждый раз с использованием текущей области видимости переменных // для заданной анимации var self = this, to = Math.abs(self.previous-self.current) <=1 ? self.previous : self.current+(self.previous < self.current ? -1 : 1); $.fx.step.coverflow = function(fx) { self._refresh(fx.now, to, self.current); }; // Останавливаем предыдущую анимацию. // Анимируем изменение свойств left/top родителя текущего пункта в центр. // Используем пользовательскую анимацию обложки пункта var animation = { coverflow: 1 }; animation[this.props[2]] = ( (this.options.recenter ? -this.current * this.itemSize/2 : 0) // Центрируем контейнер пунктов + (this.options.center ? this.element.parent()[0]['offset'+this.props[1]]/2 - this.itemSize/2 : 0) // Вычитаем отступ контейнера пунктов - (this.options.center ? parseInt(this.element.css('padding'+this.props[3]),10) || 0 : 0) ); // Запускаем событие 'select' if(!noPropagation) this._trigger('select', null, this._uiHash()); // Выполняем процедуру анимации this.element.stop().animate(animation, { duration: this.options.duration, easing: 'easeOutQuint' }); } |
Код, приведенный выше сначала определяет, справа или слева находится обложка (различные значения параметров используются в зависимости от стороны). Затем устанавливается z-Index для обложки в зависимости от глубины ее расположения в стеке изображений, а потом вычисляются значения матрицы трансформаций и масштабирования для картинок в форме трапеций.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
this.items.each(function(i){ var side = (i == to && from-to < 0 ) || i-to > 0 ? 'left' : 'right', mod = i == to ? (1-state) : ( i == from ? state : 1 ), before = (i > from && i != to), css = { zIndex: self.items.length + (side == "left" ? to-i : i-to) }; css[($.browser.safari ? 'webkit' : 'Moz')+'Transform'] = 'matrix(1,'+(mod * (side == 'right' ? -0.2 : 0.2))+',0,1,0,0) scale('+(1+((1-mod)*0.3)) + ')'; css[self.props[2]] = ( (-i * (self.itemSize/2)) + (side == 'right'? -self.itemSize/2 : self.itemSize/2) * mod ); //Обработка процесса для браузеров, которые не поддерживают трансформации //или не поддерживаются нашим плагином if(!supportsTransforms) { css.width = self.itemWidth * (1+((1-mod)*0.5)); css.height = css.width * (self.itemHeight / self.itemWidth); css.top = -((css.height - self.itemHeight) / 2); } $(this).css(css); }); |
Рассмотрим использование CoverFlow. Для использования CoverFlow нужно определить список пунктов, для которого будет использоваться эффект. Задействуем простую структуру HTML кода. Также определяем разметку для слайдера и списка названий, которые выводится ниже CoverFow.
1 2 3 4 5 6 7 8 9 10 |
<div> <div id="coverflow"><img data-album="Plastic Beach" data-artist="Gorillaz" alt="" src="images/gorillaz-plasticbeach.jpg"> <img data-album="Hurley" data-artist="Weezer" alt="" src="images/weezer-hurley.jpg"> <img data-album="Come Around Sunshine" data-artist="Kings Of Leon" alt="" src="images/kingsofleon-comearoundsunshine.jpg"> <img data-album="Born Free" data-artist="Kid Rock" alt="" src="images/kidrock-bornfree.jpg"> <img data-album="Recovery" data-artist="Eminem" alt="" src="images/recovery-recovery.jpg"> <img data-album="The Band Perry" data-artist="The Band Perry" alt="" src="images/thebandperry-thebandperry.jpg"> etc.</div> <div id="imageCaption">Текст для примера</div> <div id="slider"> </div> </div> |
Для контейнера CoverFlow, списка изображений (#coverflow) и самого изображения используются следующие стили CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
div.wrapper { height: 390px; width: 800px; /*600*/ padding: 10px; overflow: hidden; position: relative; margin: 0 auto; } #coverflow { height: 300px; width: 2600px; padding: 42px; position: absolute; top: 0px; left: 0px; margin-top: 50px; } #coverflow img { width: 260px; height: 260px; float: left; position: relative; margin: -35px; } |
Демонстрация использует также дополнительные действия с помощью JavaScript. Они включены в отдельный файл app.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
//Кэшируем ключевые компоненты var html = $('#demo-frame div.wrapper').html(); var imageCaption = $('#imageCaption'); $('#demo-frame div.wrapper').parent().append(html).end().remove(); $sliderCtrl = $('#slider'); $coverflowCtrl = $('#coverflow'); $coverflowImages = $coverflowCtrl.find('img'); $sliderVertical = $("#slider-vertical"); //Значения по умолчанию var defaultItem = 0; var listContent = ""; //Устанавливаем индекс изображения по умолчанию setDefault(7); //Устанавливаем пункт, который будет выводиться при загрузке //Корректируем индекс function setDefault($n){ defaultItem = $n-1; } //Устанавливаем подись изображения function setCaption($t){ imageCaption.html($t); } //Инициализируем CoverFlow $coverflowCtrl.coverflow({ item: defaultItem, duration:1200, select: function(event, sky) { skipTo(sky.value); } }); //Инициализируем горизонтальный слайдер $sliderCtrl.slider({ min: 0, max: $('#coverflow > *').length-1, value: defaultItem, slide: function(event, ui) { $coverflowCtrl.coverflow('select', ui.value, true); $('.coverflowItem').removeClass('ui-selected'); $('.coverflowItem:eq(' + (ui.value) +')').addClass('ui-selected'); setCaption($('.coverflowItem:eq(' + (ui.value) +')').html()); } }); //CoverFlow проводим до нужного пункта function skipTo($itemNumber){ $sliderCtrl.slider( "option", "value", $itemNumber); $coverflowCtrl.coverflow('select', $itemNumber, true); $('.coverflowItem').removeClass('ui-selected'); $('.coverflowItem:eq(' + ($itemNumber) +')').addClass('ui-selected'); setCaption($('.coverflowItem:eq(' + ($itemNumber) +')').html()); } //Генерируем текстовый список под изображениями обложек $coverflowImages.each(function(index, value) { $artist = $(this).data('artist'); $album = $(this).data('album'); try{ listContent += "<li class='ui-state-default coverflowItem' data-itemlink='" + (index) +"'>" + $artist + " - " + $album +"</li>"; }catch(e){ } }); //Устанавливаем все органы управления на текущий элемент $('#sortable').html(listContent); skipTo(defaultItem); //Назначаем обработку события click для изображений обложек $('body').delegate('.coverflowItem','click', function(){ skipTo($(this).data('itemlink')); }); |
Теперь осуществляем навигацию с помощью клавиатуры:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//Обрабатываем события клавиатуры $(document).keydown(function(e){ $current = $sliderCtrl.slider('value'); switch(e.keyCode){ case 37: if($current > 0){ $current--; skipTo($current); } break; case 39: if($current < $('#coverflow > *').length-1){ $current++; skipTo($current); } break; } }); |
И последним шагом будет навигация с помощью колесика мыши:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
$(document).mousewheel(function(event, delta){ var speed = 1; var sliderVal = $sliderCtrl.slider("value");//Получаем текущее значение слайдера var coverflowItem = 0; var cflowlength = $('#coverflow > *').length-1; //Проверяем delta для определения направления прокрутки колесика мыши if(delta > 0 && sliderVal > 0){ sliderVal -=1; }else{ if(delta < 0 && sliderVal < cflowlength){ sliderVal +=1; } } var leftValue = -((100-sliderVal)*difference/100);// Вычисляем положение верхя содержания из положения слайдера if (leftValue>0) leftValue = 0;// Останавливаем чрезмерную прокурутку вниз if (Math.abs(leftValue)>difference) leftValue = (-1)*difference;// Останавливаем прокрутку содержания за нужную точку coverflowItem = Math.floor(sliderVal); skipTo(coverflowItem); event.preventDefault();//Останавливаем обработку события по умолчанию }); |
Материал взят из зарубежного источника. И представлен исключительно в ознакомительных целях.
Читайте также:
Опубликовал Cooper 16.02.2012 в 21:32, в категории jQuery. Вы можете следить за комментариями через RSS 2.0. Вы можете перейти в конец записи и оставить комментарий. Пинги запрещены. |