Статьи

Создание jQuery Image Scroller

В этом уроке мы собираемся создать скроллер изображений, используя отличные анимационные функции jQuery и, в общем, повеселиться с кодом. Изображение скроллеры, конечно, ничего нового; их версии выходят все время. Многие из них, однако, инициированы пользователем; Это означает, что для изменения отображаемого в данный момент содержимого посетитель должен нажать кнопку или выполнить другое действие. Этот скроллер будет отличаться тем, что он будет полностью автономным и начнет прокручиваться после загрузки страницы.


Готовый виджет будет полностью кросс-браузерным и будет работать так, как ожидается в последних версиях всех наиболее распространенных браузеров. Мы также добавим некоторое взаимодействие, добавив элементы управления, которые позволяют посетителю изменять направление анимации. В этом учебном пособии мы будем работать только с jQuery и небольшим количеством HTML и CSS, и мы сможем запустить примеры без полной настройки веб-сервера.


Давайте сначала создадим базовую HTML-страницу; на новой странице в вашем текстовом редакторе добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE HTML PUBLIC «-//W3C//DTD HTML 4.01//EN» «http://www.w3.org/TR/html4/strict.dtd»>
<html>
  <head>
    <link rel=»stylesheet» type=»text/css» href=»imageScroller.css»>
    <meta http-equiv=»Content-Type» content=»text/html; charset=utf-8″>
    <title>imageScroller Image Carousel</title>
  </head>
  <body>
    <div id=»outerContainer»>
      <div id=»imageScroller»>
      <div id=»viewer» class=»js-disabled»>
        <a class=»wrapper» href=»http://www.apple.com» title=»Apple»><img class=»logo» id=»apple» src=»logos/apple.jpg» alt=»Apple»></a>
        <a class=»wrapper» href=»http://mozilla-europe.org/en/firefox» title=»Firefox»><img class=»logo» id=»firefox» src=»logos/firefox.jpg» alt=»Firefox»></a>
        <a class=»wrapper» href=»http://jquery.com» title=»jQuery»><img class=»logo» id=»jquery» src=»logos/jquery.jpg» alt=»jQuery»></a>
        <a class=»wrapper» href=»http://twitter.com» title=»Twitter»><img class=»logo» id=»twitter» src=»logos/twitter.jpg» alt=»Twitter»></a>
        <a class=»wrapper» href=»http://jqueryui.com» title=»jQuery UI»><img class=»logo» id=»jqueryui» src=»logos/jqueryui.jpg» alt=»jQuery UI»></a>
      </div>
      </div>
    </div>
    <script type=»text/javascript» src=»http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js»></script>
    <script type=»text/javascript»>
    $(function() {
 
      });
    </script>
  </body>
</html>

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

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

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

Самый внутренний контейнер — это элемент, который будет использоваться для просмотра изображений. Этот элемент имеет класс js-disabled, который будет использоваться исключительно для посетителей, у которых отключен JavaScript. Мы будем использовать этот класс, чтобы уменьшить каждое из изображений с помощью CSS, чтобы все они были доступны для просмотра.

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


После ссылки на jQuery у нас есть собственный элемент сценария с ярлыком jQuery document.ready , ожидающий, пока мы добавим код, который оживит виджет. Однако прежде чем сделать это, давайте просто быстро добавим CSS. В другом новом файле в вашем текстовом редакторе добавьте следующие селекторы и правила стиля:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
/* js-disabled class — set image sizes so they all fit in the viewer */
.js-disabled img { width:100px;
 
#outerContainer { width:542px;
#imageScroller { width:542px;
#viewer { width:522px;
#imageScroller a:active, #imageScroller a:visited { color:#000000;
#imageScroller a img { border:0;
#controls { width:534px;
#controls a { width:37px;
#controls a:active, #controls a:visited { color:#0d0d0d;
#title { color:#ffffff;
#rtl { background:url(images/rtl.png) no-repeat;
#rtl:hover { background:url(images/rtl_over.png) no-repeat;
#ltr { background:url(images/ltr.png) no-repeat;
#ltr:hover { background:url(images/ltr_over.png) no-repeat;

Если JavaScript отключен и во время загрузки страницы все изображения будут доступны для просмотра

Сохраните это как imageScroller.css в той же папке, что и веб-страница. Сначала у нас есть селектор класса, который нацелен на наш класс js-disabled ; с помощью этих правил мы просто устанавливаем размеры изображений так, чтобы они были достаточно маленькими, чтобы складываться рядом друг с другом по ширине виджета. Если JavaScript отключен, и пока страница загружается, все изображения будут доступны для просмотра — очень быстрый и простой запасной вариант, но не обязательно надежный и, конечно, не полный Прогрессивное улучшение. Значения, указанные для ширины и высоты, должны будут варьироваться в зависимости от количества изображений в средстве просмотра.

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

Готовый продукт

Некоторые из CSS мы установим в JavaScript через мгновение, а некоторые элементы, на которые мы нацеливаемся в CSS, еще не существуют, но это все, что нужно, чтобы войти в файл CSS.


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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//remove js-disabled class
$(«#viewer»).removeClass(«js-disabled»);
             
//create new container for images
$(«<div>»).attr(«id», «container»).css({
  position:»absolute»
}).width($(«.wrapper»).length * 170).height(170).appendTo(«div#viewer»);
                 
//add images to container
$(«.wrapper»).each(function() {
  $(this).appendTo(«div#container»);
});
                 
//work out duration of anim based on number of images (1 second for each image)
var duration = $(«.wrapper»).length * 1000;
                 
//store speed for later
var speed = (parseInt($(«div#container»).width()) + parseInt($(«div#viewer»).width())) / duration;
                                 
//set direction
var direction = «rtl»;
                 
//set initial position and class based on direction
(direction == «rtl») ?

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

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

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

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

Наконец, мы устанавливаем начальную позицию нового контейнера; так как анимация в настоящее время установлена ​​на rtl, нам нужно расположить новый контейнер изображений так, чтобы его левый край был установлен на правый край зрителя. Если мы установим анимацию на ltr, правый край элемента будет выровнен с левым краем контейнера. Мы определяем направление с помощью троичного условного JavaScript. Помимо его позиции, мы также даем новому контейнеру имя класса, соответствующее его направлению, которое мы можем проверить в разных точках скрипта.

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

01
02
03
04
05
06
07
08
09
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
//animator function
var animator = function(el, time, dir) {
                  
  //which direction to scroll
  if(dir == «rtl») {
                       
    //add direction class
    el.removeClass(«ltr»).addClass(«rtl»);
                             
    //animate the el
    el.animate({ left:»-» + el.width() + «px» }, time, «linear», function() {
                                         
    //reset container position
    $(this).css({ left:$(«div#imageScroller»).width(), right:»» });
                             
    //restart animation
    animator($(this), duration, «rtl»);
                             
    //hide controls if visible
    ($(«div#controls»).length > 0) ?
                             
    });
  } else {
                     
    //add direction class
    el.removeClass(«rtl»).addClass(«ltr»);
                     
    //animate the el
    el.animate({ left:$(«div#viewer»).width() + «px» }, time, «linear», function() {
                                             
      //reset container position
      $(this).css({ left:0 — $(«div#container»).width() });
                             
      //restart animation
      animator($(this), duration, «ltr»);
                             
      //hide controls if visible
      ($(«div#controls»).length > 0) ?
    });
  }
}

Функция аниматора принимает три аргумента; элемент для анимации, продолжительность времени, в течение которого должна выполняться анимация, и направление, в котором элемент должен быть анимирован. Функция разбита на два отдельных блока, один для анимации rtl, а другой для ltr.

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

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

Мы задаем строку linear в качестве третьего аргумента метода animate, который представляет собой функцию замедления, и устанавливаем анимацию для продолжения с одинаковой скоростью от начала до конца; если мы не установим это, анимация заметно ускорится и замедлится в начале и конце анимации соответственно.

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

Чтобы запустить анимацию при загрузке страницы, нам нужно вызвать функцию, которую мы только что определили; добавьте следующий вызов функции:

1
2
//start anim
animator($(«div#container»), duration, direction);

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

Готовый продукт

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
//pause on mouseover
$(«a.wrapper»).live(«mouseover», function() {
                   
  //stop anim
  $(«div#container»).stop(true);
                     
  //show controls
($(«div#controls»).length == 0) ?
($(«a#rtl»).length == 0) ?
($(«a#ltr»).length == 0) ?
                     
  //variable to hold trigger element
  var title = $(this).attr(«title»);
                     
  //add p if doesn’t exist, update it if it does
  ($(«p#title»).length == 0) ?
});

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

Мы используем живой метод jQuery (впервые в версии 1.3!), Чтобы прикрепить обработчик к элементам и указать анонимную функцию, которая будет выполняться при возникновении события.

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

Мы проверяем, существует ли панель управления, и, если она не создается, мы создаем новый элемент div, присваиваем ему идентификатор, чтобы он выбирал наши правила стиля и добавлял его во внешний контейнер. Затем мы используем метод css jQuery, чтобы установить непрозрачность в кросс-браузерном режиме, чтобы избежать необходимости нацеливания на разные браузеры с помощью нашего CSS, и сдвинуть элементы управления на место.

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

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

1
2
//add p if doesn’t exist, update it if it does
($(«p#title»).length == 0) ?

Причина этого в том, что нет никакой двусмысленности относительно того, что относится к $ (this). Использование приведенного выше кода работает, но выдает ошибки, которые хотя и не являются фатальными, но все же не настолько обнадеживают для потенциальных пользователей виджета. Использование переменной просто гарантирует, что этих ошибок избежать. Панель управления, когда она видна, выглядит как на следующем снимке экрана:

Готовый продукт

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
//restart on mouseout
$(«a.wrapper»).live(«mouseout», function(e) {
                   
  //hide controls if not hovering on them
  (e.relatedTarget == null) ?
                     
  //work out total travel distance
  var totalDistance = parseInt($(«div#container»).width()) + parseInt($(«div#viewer»).width());
                                                         
  //work out distance left to travel
  var distanceLeft = ($(«div#container»).hasClass(«ltr»)) ?
                     
  //new duration is distance left / speed)
  var newDuration = distanceLeft / speed;
                 
  //restart anim
  animator($(«div#container»), newDuration, $(«div#container»).attr(«class»));
 
});

Мы снова используем живой метод jQuery, но на этот раз мы также передаем необработанный объект события в нашу анонимную функцию обратного вызова. Мы сразу используем этот объект, чтобы увидеть, переместился ли указатель на панель управления. Если это не так, мы скрываем элементы управления, но если это так, мы ничего не делаем и продолжаем перезапускать анимацию. Обратите внимание, как мы используем вложенную троичную структуру, которая эквивалентна условному условию if else.

Основная цель анонимной функции — перезапустить анимацию, но прежде чем мы сможем это сделать, нам нужно определить продолжительность анимации; мы не можем жестко закодировать значение, потому что контейнер изображения будет перемещен. Начальная продолжительность была установлена ​​на 1 секунду для каждого изображения, в этом примере 5 секунд. Если в средстве просмотра осталось только одно изображение, и мы снова установили анимацию на 5 секунд, анимация будет продолжаться заметно медленнее.

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

Если анимация происходит слева направо, расстояние, которое нужно пройти, является атрибутом левого стиля контейнера изображения (полученного с помощью метода css jQuery), добавляемого к ширине контейнера изображения, вычитаемого из общего расстояния. Однако, если контейнер изображений перемещается справа налево, расстояние, которое нужно пройти, равно ширине контейнера изображений минус левый атрибут стиля, вычтенный из общего расстояния. Методы width и css jQuery возвращают строковые значения, поэтому мы используем JavaScript-функцию parseInt для преобразования их в числовые значения.

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


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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
//handler for ltr button
$(«#ltr»).live(«click», function() {
                                     
  //stop anim
  $(«div#container»).stop(true);
                 
  //swap class names
  $(«div#container»).removeClass(«rtl»).addClass(«ltr»);
                                         
  //work out total travel distance
  var totalDistance = parseInt($(«div#container»).width()) + parseInt($(«div#viewer»).width());
                     
   //work out remaining distance
  var distanceLeft = totalDistance — (parseInt($(«div#container»).css(«left»)) + parseInt($(«div#container»).width()));
                     
  //new duration is distance left / speed)
  var newDuration = distanceLeft / speed;
                     
  //restart anim
  animator($(«div#container»), newDuration, «ltr»);
});

Эта функция, запускаемая при нажатии кнопки слева направо, является относительно простой и содержит код, очень похожий на тот, который мы уже использовали; сначала мы остановим текущую анимацию (она возобновится, когда посетитель наведет указатель на панель управления), а затем поменяем имя класса так, чтобы оно соответствовало новому направлению движения. Затем мы определяем новую продолжительность анимации так же, как мы делали это раньше, прежде чем, наконец, снова вызвать нашу функцию аниматора. Это просто обработчик для кнопки ltr; обработчик для кнопки rtl практически идентичен, но использует правильный расчет для противоположного направления движения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
//handler for rtl button
$(«#rtl»).live(«click», function() {
                                         
  //stop anim
  $(«div#container»).stop(true);
                     
  //swap class names
  $(«div#container»).removeClass(«ltr»).addClass(«rtl»);
                     
  //work out total travel distance
  var totalDistance = parseInt($(«div#container»).width()) + parseInt($(«div#viewer»).width());
 
  //work out remaining distance
  var distanceLeft = totalDistance — (parseInt($(«div#viewer»).width()) — (parseInt($(«div#container»).css(«left»))));
                     
  //new duration is distance left / speed)
  var newDuration = distanceLeft / speed;
                 
  //restart anim
  animator($(«div#container»), newDuration, «rtl»);
});

Теперь это весь код, который нам нужно написать. Если вы запустите страницу в браузере на этом этапе, вы увидите, что виджет работает так, как задумано.


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