12. Управление CSS-свойствами на JavaScript
Функция animateCSS
![]() |
Ниже приводится код функции animateCSS из книги Девида Флэнагана «JavaScript, подробное руководство, 5-ое издание». Эта функция поможет создавать JavaScript-анимацию на базе CSS. Вы можете подключать файл animateCSS.js к своим собственным скриптам. Код функции подробно прокомментирован. |
// This code is from the book JavaScript: The Definitive Guide,
// 5th Edition, by David Flanagan. Copyright 2006 O'Reilly Media,
// Inc. (ISBN #0596101996)
/**
* ------------------
* Файл animateCSS.js
* ------------------
* Аргументы функции:
* element -- ссылка на анимируемый HTML-элемент
* numFrames -- общее число кадров в анимации
* timePerFrame -- количество миллисекунд отображения каждого кадра
* animation -- объект, определяющий анимацию
* whendone -- необязательная функция, которая будет вызвана после
* завершения анимации. Если функция указана, ей в
* качестве аргумента передается значение аргумента
* element
* Функция animateCSS просто определяет платформу для анимации.
* Выполняемую анимацию задают свойства объекта animation. Каждое
* свойство должно иметь то же имя, что и свойство CSS-стиля. Значением
* каждого свойства должна быть функция, возвращающая значения для
* этого свойства стиля. Каждой функции передаётся номер кадра и общий
* промежуток времени, прошедший с начала анимации, а функция может
* использовать это для вычисления значения стиля, которое она должна
* вернуть для данного кадра. Например, чтобы анимировать изображение
* так, чтобы оно передвигалось из левого верхнего угла, вы можете
* вызвать функцию animateCSS так:
*
* animateCSS(image, 25, 50, // Анимировать в течении 25 кадров
* // по 50 mc каждый
* { // Установить свойства left и top для каждого кадра:
* top: function(frame,time) { return frame*8 + "px"; },
* left: function(frame,time) { return frame*8 + "px"; }
* });
**/
function animateCSS(element, numFrames, timePerFrame,
animation, whendone)
{
var frame = 0; // Текущий номер кадра
var time = 0; // Общее веремя анимации, прошедшее с начала
// Задать вызов displayNextFrame каждые timePerFrame миллисекунд.
// Так будет отображаться каждый кадр анимации.
var intervalId = setInterval(displayNextFrame, timePerFrame);
// На этом работа animateCSS завершается, но предыдущая строка
// гарантирует, что следующая вложенная функция будет вызываться для
// каждого кадра анимации.
function displayNextFrame()
{
if (frame >= numFrames) // Проверить, не закончилась ли анимация
{
clearInterval(intervalId); // Если да -- прекратить вызовы,
if (whendone) whendone(element); // вызвать функцию whendone
return; // (если задана), и завершить
} // работу
// Обойти в цикле все свойства, определяемые объектом анимации
for(var cssprop in animation)
{
// Для каждого свойства вызвать его функцию, передавая
// ей номер кадра и прошедшее время. Используем возвращаемое
// функцией значение в качестве нового значения соответствующего
// свойства стиля для указанного элемента. Используем блок
// try/catch, чтобы игнорировать любые исключительные ситуации,
// возникающие из-за неверных возвращаемых значений.
try
{
element.style[cssprop] = animation[cssprop](frame, time);
} catch(e) {}
}
frame++; // Увеличить номер кадра
time += timePerFrame; // Увеличить прошедшее время
}
}
Пояснение фрагмента кода c инструкцией try/catch
Инструкция try/catch реализует механизм обработки исключений (ошибок времени исполнения). Конструкция try размечает фрагмент кода, в котором будут обрабатываться исключения. Конструкция catch работает тогда и только тогда, когда в блоке try возникает исключение (ошибка).
Общий синтаксис:
try
{
// Здесь помещают код, за которым ведется наблюдение.
// Если в коде возникнет исключение, начнет работать блок catch.
}
catch(e)
{
// Инструкции в этом блоке будут работать тогда и только тогда,
// когда в блоке try возникает исключение (ошибка). Инструкции
// в этом блоке могут использовать локальную переменную e,
// ссылающуюся на объект класса Error (детализация ошибки)
}
Инструкция try/catch блокирует появление на экране системного окна с сообщением об ошибке. Она позволяет обработать ошибку программным путем внутри блока catch или игнорировать её (как это сделано внутри animateCSS).
Обратите внимание, в фунции animateCSS создается таймер
var intervalId = setInterval(displayNextFrame, timePerFrame);
который будет вызывать функцию displayNextFrame каждые timePerFrame миллисекунд. Но функция displayNextFrame является внутренней функцией animateCSS, и использует локальные переменные frame и time объемлющей функции. Что это означает? Это означает, что образуется замыкание, и объект вызова функции animateCSS не будет уничтожен после завершения её работы.
Построим несколько примеров с использованием функции animateCSS. Для этого запишем приведенный выше код Девида Флэнагана в файл animateCSS.js, и подключим его к странице обычным способом при помощи элемента SCRIPT в головной части HTML-кода. Начнём с повторения примера 2 «Веселая кнопка».
Рассмотрим следующие две задачи:
- Выдвинуть элемент от границы или задвинуть за границу родительского блока (элемент перемещается). Части элемента за границами родительского блока невидимы (отсекаются).
- Постепенно открыть (спрятать) элемент (сам элемент неподвижен, двигается «шторка», которая его открывает или закрывает).
Первая задача решается с помощью CSS-свойства overflow со значением hidden и позиционированием элемента за пределы (из пределов) родительского блока.
Вторая задача решается при помощи динамического изменения значения свойства clip (шторка), заданного для родительского элемента.
Свойство определяет, как показывать содержимое блока, которое в нем не помещается.
Свойство можно применять только к блочным или строчным замещаемым элементам (картинкам, например).
Значения:
- visible — значение по умолчанию. Содержимое будет видимо за границами блока.
- hidden — содержимое отсекается краями блока.
- scroll — содержимое отсекается краями блока, но у блока появляются постоянные полосы прокрутки, и содержимое можно увидеть.
- auto — работает как scroll, если содержимое выходит за границу блока. Если содержимое вмещается в блок, полосы прокрутки не отображаются.
Свойства применимо только к абсолютно позиционированным элементам, оно задает прямоугольную область отсечения, вне которой содержимое элемента отсекается. То есть вне прямоугольника, заданного свойством clip, содержимое элемента невидимо.
Значения:
- auto — работает по умолчанию. Область отсечения совпадает с размерами элемента, для которого свойство задано.
- rect(top right bottom left) — задает прямоугольную область отсечения. При этом значения top, right, bottom и left означают расстояния от верхнего левого угла элемента, для которого свойство задано. В качестве значений top, right, bottom и left можно использовать единицы размера и auto (устанавливает размер по соответствующему размеру элемента).
Пусть блок box имеет размеры 300x200. Приведенное ниже определение задает область отсечения размером 150х100, расположенную в левом верхнем углу блока box:
#box
{
position:absolute;
width:300px;
height:200px;
clip: rect(0 150 100 0);
}
Вернемся к двум поставленным задачам:
- Выдвинуть элемент от границы или задвинуть за границу родительского блока (элемент перемещается). Части элемента за границами родительского блока невидимы (отсекаются).
- Постепенно открыть (спрятать) элемент (элемент неподвижен, двигается «шторка»).
Запишем HTML-код:
<DIV id="parentbox">
<DIV id="box">
<IMG id="pic" src="pic/01.png" width=500 height=313 alt="" title="">
</DIV>
</DIV>
В стилевых определениях (в CSS-файле) пропишем относительное позиционирование для блока parentbox и абсолютное для блока box. Элемент IMG является содержимым блока box.
Относительное позиционирование для parentbox обеспечит две важные вещи: во-первых, блок parentbox останется в потоке, во-вторых, координаты абсолютно позиционированного блока box будут отсчитываться от родителя parentbox.
Будем решать две поставленные задачи по отношению к картинке — содержимому блока box.
Первая задача решается при помощи правила overflow:hidden, заданного для блока box и созданием анимации, которая будет управлять свойством top элемента IMG.
Вторая задача решается при помощи правила clip: rect(0 auto x 0), в котором x меняется в анимационном цикле (от 0 до высоты картинки, при её открытии, и от высоты картинки до 0 при её сокрытии).
Решение второй задачи показано в примере 5, а первая задача включена в состав набора контрольных заданий.