Информация к новости
  • Просмотров: 308
  • Автор: sulicompany
  • Дата: 30-05-2012, 01:35
 (голосов: 0)
30-05-2012, 01:35

Эластичное слайдшоу с миниатюрами

Категория: Программирование » jQuery


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

Для реализации функции адаптации будет использоваться смесь техник javascript и CSS.

 

Разметка HTML

Мы создадим два неупорядоченных списка. Один будет использоваться для основного слайдера, а другой - для миниатюр навигации, расположенных под большим изображением. Элементы "большого слайдера" содержат изображения и заголовки h2 и h3:

01<div id="ei-slider" class="ei-slider">
02    <ul class="ei-slider-large">
03        <li>
04            <img src="images/large/1.jpg" alt="image01" />
05            <div class="ei-title">
06                <h2>Креативно</h2>
07                <h3>Geek</h3>
08            </div>
09        </li>
10        <li>...</li>
11    </ul>
12    <ul class="ei-slider-thumbs">
13        <li class="ei-slider-element">Current</li>
14        <li>
15            <a href="#">Слайд 1</a>
16            <img src="images/thumbs/1.jpg" alt="thumb01" />
17        </li>
18        <li>...</li>
19    </ul>
20</div>

Элемент списка миниатюр содержит ссылку и изображение. При этом первый пункт списка - абсолютный элемент с классом ei-slider-element.

 

CSS

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

1.ei-slider{
2    positionrelative;
3    width100%;
4    max-width1920px;
5    height400px;
6    margin0 auto;
7}

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

01.ei-slider-loading{
02    width100%;
03    height100%;
04    positionabsolute;
05    top0px;
06    left0px;
07    z-index:999;
08    background: rgba(0,0,0,0.9);
09    color#fff;
10    text-aligncenter;
11    line-height400px;
12}

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

1.ei-slider-large{
2    height100%;
3    width100%;
4    position:relative;
5    overflowhidden;
6}

Элементы списка содержат изображения в абсолютных позициях. В зависимости от навигации, они будут выскальзывать либо слева, либо справа:

1.ei-slider-large li{
2    positionabsolute;
3    top0px;
4    left0px;
5    overflowhidden;
6    height100%;
7    width100%;
8}

Ширина изображений будет устанавливаться кодом javascript, но ее надо определить на случай отключения javascript:

1.ei-slider-large li img{
2    width100%;
3}

Контейнер заголовков позиционируется в середине элемента списка с полем справа (чтобы не перекрывать лицо на фотографии):

1.ei-title{
2    positionabsolute;
3    right50%;
4    margin-right13%;
5    top30%;
6}

Для заголовков используются следующие стили:

01.ei-title h2, .ei-title h3{
02    text-alignright;
03}
04.ei-title h2{
05    font-size40px;
06    line-height50px;
07    font-family'Playfair Display'serif;
08    font-styleitalic;
09    color#b5b5b5;
10}
11.ei-title h3{
12    font-size70px;
13    line-height70px;
14    font-family'Open Sans Condensed'sans-serif;
15    text-transformuppercase;
16    color#000;
17}

Список навигации будет иметь маленькую высоту - 13 px. При инициализации нашего плагина мы установим ширину по умолчанию для миниатюр.

1.ei-slider-thumbs{
2    height13px;
3    margin0 auto;
4    positionrelative;
5}

Элементы списка навигации будут иметь относительные позцици:

1.ei-slider-thumbs li{
2    positionrelative;
3    floatleft;
4    height100%;
5}

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

1.ei-slider-thumbs li.ei-slider-element{
2    top0px;
3    left0px;
4    positionabsolute;
5    height100%;
6    z-index10;
7    text-indent-9000px;
8    background: rgba(0,0,0,0.9);
9}

Элемент ссылки будет иметь белую тень с небольшой добавочной темной тенью под ней. Также будет использоваться переход для плавного изменения цвета фона при наведении курсора мыши:

01.ei-slider-thumbs li a{
02    displayblock;
03    text-indent-9000px;
04    background#666;
05    width100%;
06    height100%;
07    cursorpointer;
08    box-shadow:
09        0px 1px 1px 0px rgba(0,0,0,0.3),
10        0px 1px 0px 1px rgba(255,255,255,0.5);
11        transition: background 0.2s ease;
12}
13.ei-slider-thumbs li a:hover{
14    background-color#f0f0f0;
15}

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

01.ei-slider-thumbs li img{
02    positionabsolute;
03    bottom50px;
04    opacity: 0;
05    z-index999;
06    max-width100%;
07        transition: all 0.4s ease;
08    -webkit-box-reflect:
09        below 0px -webkit-gradient(
10            linear,
11            left top,
12            left bottom,
13            from(transparent),
14            color-stop(50%transparent),
15            to(rgba(255,255,255,0.3))
16            );
17}

При наведении курсора мыши мы будем анимировать значения свойств opacity и bottom, так что элемент будет выскальзывать сверху:

1.ei-slider-thumbs li:hover img{
2    opacity: 1;
3    bottom13px;
4}

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

01@media screen and (max-width830px) {
02    .ei-title{
03        positionabsolute;
04        right0px;
05        margin-right0px;
06        width100%;
07        text-aligncenter;
08        topauto;
09        bottom10px;
10        background: rgba(255,255,255,0.9);
11        padding5px 0;
12    }
13    .ei-title h2, .ei-title h3{
14        text-aligncenter;
15    }
16    .ei-title h2{
17        font-size20px;
18        line-height24px;
19    }
20    .ei-title h3{
21        font-size30px;
22        line-height40px;
23    }
24}

Для случая отключения javascript нужно обеспечить вывод наших слайдов и скрытие навигации миниатюр:

1.ei-slider{
2    heightauto;
3}
4.ei-slider-thumbs{
5    displaynone;
6}
7.ei-slider-large li{
8    positionrelative;
9}

 

javascript

Так как мы создаем плагин, то рассмотрим сначала определение опций:

01  $.Slideshow.defaults      = {
02    // Типы анимации:
03    // "sides" : новый слайд выскальзывает слева или справа
04    // "center": новый слайд появляется в центре
05    animation           : 'sides'// sides || center
06    // Если значение true, то включается автопроигрывание слайдшоу, которое отключается при нажатии на миниатюру
07    autoplay            : false,
08    // Интервал для слайшоу
09    slideshow_interval  : 3000,
10    // Скорость анимации смены слайдов
11    speed           : 800,
12    // Функция перехода для анимации смены слайдов
13    easing          : '',
14    // Процентное соотношение анимации заголовков. Скорость будет определяться по формуле speed * titlesFactor
15    titlesFactor        : 0.60,
16    // Скорость анимации заголвоков
17    titlespeed          : 800,
18    // Функция перехода для анимации заголовоков
19    titleeasing         : '',
20    // Максимальная ширина для миниатюр в px
21    thumbMaxWidth       : 150
22};

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

Затем выводим первый слайд и, если включена опция автопроигрвания, запускаем слайдшоу. После чего инициализируются обработчики событий для изменений размеров окна и нажатий на миниатюры:

01_init               : function( options ) {
02     
03    this.options        = $.extend( true, {}, $.Slideshow.defaults, options );
04     
05    // Устанавливаем непрозрачность для элементов заголовков и изображений
06    this.$imgItems.css( 'opacity', 0 );
07    this.$imgItems.find('div.ei-title > *').css( 'opacity', 0 );
08     
09    // Индекс текущего видимого слайда
10    this.current        = 0;
11     
12    var _self           = this;
13     
14    // Предварительная загрузка изображений
15    // Добавляем статус загрузки
16    this.$loading       = $('<div class="ei-slider-loading">Loading</div>').prependTo( _self.$el );
17     
18    $.when( this._preloadImages() ).done( function() {
19         
20        // /скрываем статус загрузки
21        _self.$loading.hide();
22         
23        // Вычисляем размер и положение для каждого изображения
24        _self._setImagesSize();
25         
26        // Конфигурируем контейнер для миниатюр
27        _self._initThumbs();
28         
29        // Выводим первый пункт
30        _self.$imgItems.eq( _self.current ).css({
31            'opacity'   : 1,
32            'z-index'   : 10
33        }).show().find('div.ei-title > *').css( 'opacity', 1 );
34         
35        // Если включено автопроигрывание
36        if( _self.options.autoplay ) {
37         
38            _self._startSlideshow();
39         
40        }
41         
42        // Инициализируем события
43        _self._initEvents();
44     
45    });
46     
47},

 

Вот код используемых функций:

001_preloadImages      : function() {
002     
003    // Предварительная загрузка всех больших изображений
004     
005    var _self   = this,
006        loaded  = 0;
007     
008    return $.Deferred(
009     
010        function(dfd) {
011     
012            _self.$images.each( function( i ) {
013                 
014                $('<img/>').load( function() {
015                 
016                    if( ++loaded === _self.itemsCount ) {
017                     
018                        dfd.resolve();
019                         
020                    }
021                 
022                }).attr( 'src', $(this).attr('src') );
023             
024            });
025             
026        }
027         
028    ).promise();
029     
030},
031_setImagesSize      : function() {
032     
033    // Сохраняе ширину слайда
034    this.elWidth    = this.$el.width();
035     
036    var _self   = this;
037     
038    this.$images.each( function( i ) {
039         
040        var $img    = $(this);
041            imgDim  = _self._getImageDim( $img.attr('src') );
042             
043        $img.css({
044            width       : imgDim.width,
045            height      : imgDim.height,
046            marginLeft  : imgDim.left,
047            marginTop   : imgDim.top
048        });
049         
050    });
051 
052},
053_getImageDim        : function( src ) {
054     
055    var $img    = new Image();
056                     
057    $img.src    = src;
058             
059    var c_w     = this.elWidth,
060        c_h     = this.$el.height(),
061        r_w     = c_h / c_w,
062         
063        i_w     = $img.width,
064        i_h     = $img.height,
065        r_i     = i_h / i_w,
066        new_w, new_h, new_left, new_top;
067             
068    if( r_w > r_i ) {
069         
070        new_h   = c_h;
071        new_w   = c_h / r_i;
072     
073    }
074    else {
075     
076        new_h   = c_w * r_i;
077        new_w   = c_w;
078     
079    }
080             
081    return {
082        width   : new_w,
083        height  : new_h,
084        left    : ( c_w - new_w ) / 2,
085        top     : ( c_h - new_h ) / 2
086    };
087 
088},
089_initThumbs         : function() {
090 
091    // Устанавливаем свойство max-width элемента слайдера
092    // Также устанавливаем ширину каждого слайда по формуле 100% / на общее количество элементов
093    this.$sliderElems.css({
094        'max-width' this.options.thumbMaxWidth + 'px',
095        'width'     : 100 / this.itemsCount + '%'
096    });
097     
098    // Устанавливаем свойство max-width слайда и выводим его
099    this.$sliderthumbs.css( 'max-width'this.options.thumbMaxWidth * this.itemsCount + 'px' ).show();
100     
101},
102_startSlideshow     : function() {
103 
104    var _self   = this;
105     
106    this.slideshow  = setTimeout( function() {
107         
108        var pos;
109         
110        ( _self.current === _self.itemsCount - 1 ) ? pos = 0 : pos = _self.current + 1;
111         
112        _self._slideTo( pos );
113         
114        if( _self.options.autoplay ) {
115         
116            _self._startSlideshow();
117         
118        }
119     
120    }, this.options.slideshow_interval);
121 
122},

Функция _slideTo осуществляет переход между слайдами. В зависимости от установленных опций, слайд либо будет выскальзывать слева/справа, либо будет проявляться в центре.

01// Выводим слайд для нажатой миниатюры
02_slideTo            : function( pos ) {
03     
04    // выходим, если нажат тот же элемент или он анаимируется в данный момент
05    if( pos === this.current || this.isAnimating )
06        return false;
07     
08    this.isAnimating    = true;
09     
10    var $currentSlide   = this.$imgItems.eq( this.current ),
11        $nextSlide      = this.$imgItems.eq( pos ),
12        _self           = this,
13         
14        preCSS          = {zIndex   : 10},
15        animCSS         = {opacity  : 1};
16     
17    // Новый слайд будет выскальзывать слева или справа
18    ifthis.options.animation === 'sides' ) {
19         
20        preCSS.left     = ( pos > this.current ) ? -1 * this.elWidth : this.elWidth;
21        animCSS.left    = 0;
22     
23    }  
24     
25    // Анимация заголовков
26    $nextSlide.find('div.ei-title > h2')
27              .css( 'margin-right', 50 + 'px' )
28              .stop()
29              .delay( this.options.speed * this.options.titlesFactor )
30              .animate({ marginRight : 0 + 'px', opacity : 1 }, this.options.titlespeed,this.options.titleeasing )
31              .end()
32              .find('div.ei-title > h3')
33              .css( 'margin-right', -50 + 'px' )
34              .stop()
35              .delay( this.options.speed * this.options.titlesFactor )
36              .animate({ marginRight : 0 + 'px', opacity : 1 }, this.options.titlespeed,this.options.titleeasing )
37     
38    $.when(
39         
40        // Убираем текущии заголвоки
41        $currentSlide.css( 'z-index' , 1 ).find('div.ei-title > *').stop().fadeOut( this.options.speed / 2, function() {
42            // сбрасываем стили
43            $(this).show().css( 'opacity', 0 );
44        }),
45         
46        // Анимация вывода следующего слайдаы
47        $nextSlide.css( preCSS ).stop().animate( animCSS, this.options.speed, this.options.easing ),
48         
49        // Перемещаем индикатор в нвое положение
50        this.$sliderElem.stop().animate({
51            left    : this.$thumbs.eq( pos ).position().left
52        }, this.options.speed )
53         
54    ).done( function() {
55         
56        // Сбрасываем значения
57        $currentSlide.css( 'opacity' , 0 ).find('div.ei-title > *').css( 'opacity', 0 );
58            _self.current   = pos;
59            _self.isAnimating       = false;
60         
61        });
62         
63},

Функция _initEvents устанавливает функции для пересчета размеров изображений при изменении размеров окна и вывода нового слайда при нажатии на миниатюру:

01_initEvents         : function() {
02     
03    var _self   = this;
04     
05    // Изменение размеров окна
06    $(window).on( 'smartresize.eislideshow'function( event ) {
07         
08        // Изменяем размеры изображений
09        _self._setImagesSize();
10     
11        // Сбрасываем положение миниатюр
12        _self.$sliderElem.css( 'left', _self.$thumbs.eq( _self.current ).position().left );
13     
14    });
15     
16    // Нажатие на миниатюре
17    this.$thumbs.on( 'click.eislideshow'function( event ) {
18         
19        if( _self.options.autoplay ) {
20         
21            clearTimeout( _self.slideshow );
22            _self.options.autoplay  = false;
23         
24        }
25         
26        var $thumb  = $(this),
27            idx     = $thumb.index() - 1;
28             
29        _self._slideTo( idx );
30         
31        return false;
32     
33    });
34     
35}