Улучшить эту документацию ngAnimate
Установка
Сначала включите angular-animate.js в свой HTML:
<script src="angular.js"> <script src="angular-animate.js">
Вы можете загрузить этот файл из следующих мест:
- Google CDN
например://ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-animate.js - Bower
например:bower install angular-animate@X.Y.Z
- code.angularjs.org
например:"//code.angularjs.org/X.Y.Z/angular-animate.js"
где X.Y.Z — это версия AngularJS, которую вы используете.
Затем загрузите модуль в своё приложение, добавив его в качестве зависимого модуля:
angular.module('app', ['ngAnimate']); С этим вы готовы начать работу!
Модуль ngAnimate предоставляет поддержку анимаций на основе CSS (ключевые кадры и переходы), а также анимаций на основе JavaScript с помощью обратных вызовов. Анимации по умолчанию не включены, однако, включение ngAnimate включает анимационные хуки для приложения Angular.
Использование
Проще говоря, есть два способа использовать анимации при использовании ngAnimate: с помощью CSS и JavaScript. Первый работает чисто на основе CSS (с использованием соответствующих селекторов/стилей CSS), а второй запускает анимации, зарегистрированные через module.animation(). Для анимаций CSS и JS единственное требование — наличие соответствующего CSS class как в зарегистрированной анимации, так и в HTML-элементе, на котором будет запущена анимация.
Поддержка директив
Следующие директивы «осознают анимацию»:
| Директива | Поддерживаемые анимации |
|---|---|
| ngRepeat | ввод, вывод и перемещение |
| ngView | ввод и вывод |
| ngInclude | ввод и вывод |
| ngSwitch | ввод и вывод |
| ngIf | ввод и вывод |
| ngClass | добавление и удаление (присутствующие CSS-классы) |
| ngShow & ngHide | добавление и удаление (значение класса ng-hide) |
| form & ngModel | добавление и удаление (dirty, pristine, valid, invalid и другие валидации) |
| ngMessages | добавление и удаление (ng-active и ng-inactive) |
| ngMessage | ввод и вывод |
(Более подробную информацию можно найти, посетив документацию, связанную с каждой директивой.)
Анимации на основе CSS
Анимации на основе CSS с ngAnimate уникальны тем, что они вообще не требуют кода JavaScript. Используя CSS-класс, на который мы ссылаемся в нашем HTML- и CSS-коде, мы можем создать анимацию, которая будет обрабатываться Angular, когда базовая директива выполнит операцию.
В примере ниже показано, как можно создать анимацию enter для элемента с помощью ng-if.
<div ng-if="bool" class="fade"> Fade me in out </div> <button ng-click="bool=true">Fade In!</button> <button ng-click="bool=false">Fade Out!</button>
Обратите внимание на CSS-класс fade? Теперь мы можем создать код CSS-перехода, который ссылается на этот класс:
/* The starting CSS styles for the enter animation */
.fade.ng-enter {
transition:0.5s linear all;
opacity:0;
}
/* The finishing CSS styles for the enter animation */
.fade.ng-enter.ng-enter-active {
opacity:1;
}
Ключевой момент здесь заключается в том, что в зависимости от события анимации (которое каждый из перечисленных выше директивов вызывает в зависимости от происходящего) к элементу будут применяться два сгенерированных CSS-класса; в приведённом выше примере у нас есть .ng-enter и .ng-enter-active. Для CSS-переходов код перехода должен быть определён в стартовом CSS-классе (в данном случае .ng-enter). Класс назначения — это то, к чему будет анимироваться переход.
Если, например, мы хотим создать анимации для leave и move (ngRepeat вызывает перемещение), то мы можем сделать это, используя те же соглашения об именовании CSS:
/* now the element will fade out before it is removed from the DOM */
.fade.ng-leave {
transition:0.5s linear all;
opacity:1;
}
.fade.ng-leave.ng-leave-active {
opacity:0;
}
Мы также можем использовать CSS-ключевые кадры, ссылаясь на анимацию ключевых кадров в начальном CSS-классе:
/* there is no need to define anything inside of the destination
CSS class since the keyframe will take charge of the animation */
.fade.ng-leave {
animation: my_fade_animation 0.5s linear;
-webkit-animation: my_fade_animation 0.5s linear;
}
@keyframes my_fade_animation {
from { opacity:1; }
to { opacity:0; }
}
@-webkit-keyframes my_fade_animation {
from { opacity:1; }
to { opacity:0; }
}
Вы можете смешивать переходы и ключевые кадры, а также любые другие CSS-классы в одном элементе.
Анимации на основе CSS-классов
Анимации на основе классов (анимации, которые вызываются ngClass, ngShow, ngHide и некоторыми другими директивами) имеют немного другую систему именования. Анимации на основе классов достаточно просты, поэтому для ссылок на добавляемый и удаляемый класс можно использовать стандартный переход или ключевые кадры.
Например, если мы хотим сделать CSS-анимацию для ngHide, то мы размещаем анимацию в CSS-классе .ng-hide.
<div ng-show="bool" class="fade">
Show and hide me
</div>
<button ng-click="bool=true">Toggle</button>
<style>
.fade.ng-hide {
transition:0.5s linear all;
opacity:0;
}
</style>
Всё, что происходит здесь с ngShow/ngHide за кулисами, — это добавление/удаление класса .ng-hide (когда состояние скрытия является действительным). Поскольку ngShow и ngHide «осознают» анимацию, мы можем согласовать переход, а ngAnimate позаботится о остальном.
В дополнение к добавлению и удалению CSS-класса, ngAnimate также предоставляет два вспомогательных метода, которые можно использовать для дальнейшей настройки анимации с помощью CSS-стилей.
<div ng-class="{on:onOff}" class="highlight">
Highlight this box
</div>
<button ng-click="onOff=!onOff">Toggle</button>
<style>
.highlight {
transition:0.5s linear all;
}
.highlight.on-add {
background:white;
}
.highlight.on {
background:yellow;
}
.highlight.on-remove {
background:black;
}
</style>
Также можно использовать CSS-ключевые кадры, разместив их внутри CSS-классов.
Анимации с эффектом «ступенчатого» замедления
Анимация «ступенчатого» замедления — это набор анимаций, которые выполняются с небольшой задержкой между каждой последующей операцией, что создаёт эффект шторы. Модуль ngAnimate (версии >=1.2) поддерживает анимации с эффектом «ступенчатого» замедления, и этот эффект можно получить, создав CSS-класс ng-EVENT-stagger и прикрепив его к базовому CSS-классу, используемому для анимации. Свойство стиля, ожидаемое внутри класса stagger, может быть либо свойством transition-delay, либо свойством animation-delay (или обоими, если ваша анимация содержит как переходы, так и анимации ключевых кадров).
.my-animation.ng-enter {
/* standard transition code */
transition: 1s linear all;
opacity:0;
}
.my-animation.ng-enter-stagger {
/* this will have a 100ms delay between each successive leave animation */
transition-delay: 0.1s;
/* As of 1.4.4, this must always be set: it signals ngAnimate
to not accidentally inherit a delay property from another CSS class */
transition-duration: 0s;
}
.my-animation.ng-enter.ng-enter-active {
/* standard transition styles */
opacity:1;
}
Анимации с эффектом «ступенчатого» замедления по умолчанию работают в ngRepeat (если CSS-класс определён). Вне ngRepeat, чтобы использовать анимации с эффектом «ступенчатого» замедления самостоятельно, их можно вызвать, запустив несколько вызовов одного и того же события в $animate. Однако, ограничения заключаются в том, что каждый элемент должен иметь одинаковое значение CSS className и одинаковый родительский элемент. Операция «ступенчатого» замедления также будет сброшена, если с момента множественных вызовов $animate прошло одно или несколько кадров анимации.
Следующий код вызовет событие ng-leave-stagger для указанного элемента:
var kids = parent.children();
$animate.leave(kids[0]); //stagger index=0
$animate.leave(kids[1]); //stagger index=1
$animate.leave(kids[2]); //stagger index=2
$animate.leave(kids[3]); //stagger index=3
$animate.leave(kids[4]); //stagger index=4
window.requestAnimationFrame(function() {
//stagger has reset itself
$animate.leave(kids[5]); //stagger index=0
$animate.leave(kids[6]); //stagger index=1
$scope.$digest();
});
Анимации с эффектом «ступенчатого» замедления в настоящее время поддерживаются только для анимаций, определённых в CSS.
Класс CSS ng-animate
При анимации элемента ngAnimate применит CSS-класс ng-animate к элементу на период анимации. Это временный CSS-класс, и он будет удалён после завершения анимации (как для анимаций на основе JavaScript, так и для анимаций на основе CSS).
Поэтому к элементу можно применить анимации, используя этот временный класс непосредственно в CSS.
.zipper.ng-animate {
transition:0.5s linear all;
}
.zipper.ng-enter {
opacity:0;
}
.zipper.ng-enter.ng-enter-active {
opacity:1;
}
.zipper.ng-leave {
opacity:1;
}
.zipper.ng-leave.ng-leave-active {
opacity:0;
}
(Обратите внимание, что CSS-класс ng-animate зарезервирован и его нельзя применить к элементу напрямую, так как ngAnimate всегда будет удалять CSS-класс после завершения анимации.)
Класс ng-[event]-prepare
Это специальный класс, который можно использовать для предотвращения нежелательной мерцания/мигания содержимого перед началом фактической анимации. Класс добавляется сразу после инициализации анимации, но удаляется перед фактическим началом анимации (после ожидания $digest). Он также добавляется только для структурных анимаций (enter, move, и leave).
На практике мерцание может появляться при вложенности элементов со структурными анимациями, такими как ngIf, в элементы, имеющие анимации на основе классов, такие как ngClass.
<div ng-class="{red: myProp}">
<div ng-class="{blue: myProp}">
<div class="message" ng-if="myProp"></div>
</div>
</div>
Возможно, во время анимации enter div .message будет кратковременно виден, прежде чем начать анимироваться. В этом случае вы можете добавить стили в CSS, чтобы убедиться, что элемент остаётся скрытым перед началом анимации:
.message.ng-enter-prepare {
opacity: 0;
}
Анимации на основе JavaScript
ngAnimate также позволяет использовать анимации в коде JavaScript. Подход похож на анимации на основе CSS (где есть общий CSS-класс, на который ссылается наш HTML-код), но кроме того, нам нужно зарегистрировать анимацию JavaScript в модуле. С помощью функции модуля module.animation() мы можем зарегистрировать анимацию.
Давайте посмотрим пример анимации ввода/вывода с помощью ngRepeat:
<div ng-repeat="item in items" class="slide">
{{ item }}
</div>
Видите CSS-класс slide? Используем этот класс для определения анимации, которую мы структурируем в коде модуля, используя module.animation:
myModule.animation('.slide', [function() {
return {
// make note that other events (like addClass/removeClass)
// have different function input parameters
enter: function(element, doneFn) {
jQuery(element).fadeIn(1000, doneFn);
// remember to call doneFn so that angular
// knows that the animation has concluded
},
move: function(element, doneFn) {
jQuery(element).fadeIn(1000, doneFn);
},
leave: function(element, doneFn) {
jQuery(element).fadeOut(1000, doneFn);
}
}
}]);
Преимущество анимаций на основе JS заключается в том, что мы можем вводить другие службы и использовать расширенные библиотеки анимации, такие как greensock.js и velocity.js.
Если наш код анимации основан на классах (то есть что-то вроде ngClass, ngHide и ngShow его вызывает), то мы всё равно можем определить наши анимации внутри той же зарегистрированной анимации, однако входные аргументы функции немного отличаются:
<div ng-class="color" class="colorful"> this box is moody </div> <button ng-click="color='red'">Change to red</button> <button ng-click="color='blue'">Change to blue</button> <button ng-click="color='green'">Change to green</button>
myModule.animation('.colorful', [function() {
return {
addClass: function(element, className, doneFn) {
// do some cool animation and call the doneFn
},
removeClass: function(element, className, doneFn) {
// do some cool animation and call the doneFn
},
setClass: function(element, addedClass, removedClass, doneFn) {
// do some cool animation and call the doneFn
}
}
}]);
CSS + JS анимации вместе
AngularJS 1.4 и выше предпринял шаги, чтобы сделать объединение CSS и JS анимаций более гибким. Однако, в отличие от предыдущих версий Angular, определение CSS и JS анимаций, работающих с одним CSS-классом, больше не работает. Поэтому пример ниже будет приводить только к тому, что JS анимации возьмут на себя управление анимацией:
<div ng-if="bool" class="slide"> Slide in and out </div>
myModule.animation('.slide', [function() {
return {
enter: function(element, doneFn) {
jQuery(element).slideIn(1000, doneFn);
}
}
}]);
.slide.ng-enter {
transition:0.5s linear all;
transform:translateY(-100px);
}
.slide.ng-enter.ng-enter-active {
transform:translateY(0);
}
Это означает, что CSS и JS анимации не могут использоваться вместе? У JS-анимаций всегда более высокий приоритет? Мы можем компенсировать отсутствие CSS-анимаций, используя службу $animateCss для запуска наших собственных модифицированных CSS-анимаций напрямую из нашего собственного кода JS-анимации:
myModule.animation('.slide', ['$animateCss', function($animateCss) {
return {
enter: function(element) {
// this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`.
return $animateCss(element, {
event: 'enter',
structural: true
});
}
}
}]);
Преимущество здесь заключается в том, что мы можем экономить полосу пропускания, придерживаясь нашего кода CSS-анимации, и нам не нужно полагаться на стороннюю библиотеку анимации.
Сервис $animateCss очень мощный, так как мы можем передавать все типы дополнительных свойств, которые будут оценены и переданы в анимацию перехода CSS или ключевую кадровую анимацию. Например, если мы хотим анимировать высоту элемента, добавляя и удаляя классы, мы можем сделать это, предоставив эти данные в $animateCss напрямую:
myModule.animation('.slide', ['$animateCss', function($animateCss) {
return {
enter: function(element) {
return $animateCss(element, {
event: 'enter',
structural: true,
addClass: 'maroon-setting',
from: { height:0 },
to: { height: 200 }
});
}
}
}]);
Теперь мы можем заполнить остальную часть кода перехода CSS:
/* the transition tells ngAnimate to make the animation happen */
.slide.ng-enter { transition:0.5s linear all; }
/* this extra CSS class will be absorbed into the transition
since the $animateCss code is adding the class */
.maroon-setting { background:red; }
И $animateCss рассчитает остальное. Просто убедитесь, что обратный вызов done() вызывает функцию doneFn, чтобы сигнализировать о завершении анимации.
Чтобы узнать больше о возможностях, посетите $animateCss service.
Якорная анимация (через ng-animate-ref)
ngAnimate в AngularJS 1.4 поставляется с возможностью кросс-анимации элементов между структурными областями приложения (например, представлениями), объединяя элементы с помощью атрибута, называемого ng-animate-ref.
Предположим, например, что у нас есть два представления, управляемые ng-view, и мы хотим показать, что существует связь между двумя компонентами, расположенными внутри этих представлений. Используя атрибут ng-animate-ref , мы можем определить, что два компонента связаны вместе, и мы можем прикрепить анимацию, которая запускается при изменении представления.
Предположим, например, что у нас есть следующий код шаблона:
<!-- index.html --> <div ng-view class="view-animation"> </div> <!-- home.html --> <a href="#/banner-page"> <img src="./banner.jpg" class="banner" ng-animate-ref="banner"> </a> <!-- banner-page.html --> <img src="./banner.jpg" class="banner" ng-animate-ref="banner">
Теперь, когда представление меняется (после нажатия ссылки), ngAnimate проанализирует содержимое HTML, чтобы проверить, есть ли соответствие ссылки между компонентами в покидаемом представлении и входящем представлении. Он будет сканировать как удаляемое (leave), так и вставляемое (enter) представления, чтобы увидеть, есть ли какие-либо сопряженные DOM-элементы, содержащие совпадающее значение ref.
Два изображения совпадают, так как они имеют одинаковое значение ref. ngAnimate теперь создаст элемент транспортировки (который является клоном первого элемента изображения) и попытается анимировать его в позицию второго элемента изображения в следующем представлении. Для работы анимации будет добавлен специальный класс CSS, называемый ng-anchor к элементу транспортировки.
Теперь мы можем прикрепить переход к классу CSS .banner.ng-anchor, и ngAnimate будет обрабатывать весь переход за нас, а также добавление и удаление любых изменений классов CSS между элементами:
.banner.ng-anchor {
/* this animation will last for 1 second since there are
two phases to the animation (an `in` and an `out` phase) */
transition:0.5s linear all;
}
Мы также должны включить анимации для вставляемых и удаляемых представлений (иначе якорная анимация не будет возможна, так как новое представление будет вставлено сразу же).
.view-animation.ng-enter, .view-animation.ng-leave {
transition:0.5s linear all;
position:fixed;
left:0;
top:0;
width:100%;
}
.view-animation.ng-enter {
transform:translateX(100%);
}
.view-animation.ng-leave,
.view-animation.ng-enter.ng-enter-active {
transform:translateX(0%);
}
.view-animation.ng-leave.ng-leave-active {
transform:translateX(-100%);
}
Теперь мы можем вернуться к анимации якоря. Когда происходит анимация, происходят две стадии: стадия out и стадия in. Стадия out происходит первой, и это когда элемент анимируется из исходной точки. После завершения этой анимации происходит стадия in , которая анимирует элемент к его пункту назначения. Причина, по которой есть две анимации, заключается в том, чтобы предоставить достаточно времени для того, чтобы анимация вхождения нового элемента была готова.
В приведенном выше примере настраивается переход для фаз вхождения и выхода, но мы также можем напрямую нацеливаться на фазы выхода или вхождения через ng-anchor-out и ng-anchor-in.
.banner.ng-anchor-out {
transition: 0.5s linear all;
/* the scale will be applied during the out animation,
but will be animated away when the in animation runs */
transform: scale(1.2);
}
.banner.ng-anchor-in {
transition: 1s linear all;
}
Демонстрация якорной анимации
Как происходит транспортировка элемента?
При выполнении анимации якоря ngAnimate клонирует исходный элемент и позиционирует его точно там, где исходный элемент находится на экране, используя абсолютное позиционирование. Клонированный элемент будет размещен внутри корневого элемента приложения (где был определен ng-app), и все классы CSS исходного элемента будут применены. Затем элемент будет анимирован в анимации out и in и, в конечном итоге, достигнет координат и будет соответствовать размерам целевого элемента. В течение всей анимации к исходному и целевому элементам будет применен класс CSS .ng-animate-shim для их скрытия (стили CSS для класса: visibility:hidden). После достижения якорем пункта назначения он будет удален, и целевой элемент станет видимым, поскольку класс шима будет удален.
Как обрабатывается морфинг?
Якорная анимация CSS полагается на переходы и ключевые кадры, и внутренний код достаточно интеллектуален, чтобы определить, какие классы CSS отличаются между исходным и целевым элементами. Эти различные классы CSS будут добавляться/удаляться в элементе якоря, и будет применен переход (переход, предоставленный в классе якоря). Короче говоря, ngAnimate определит, какие классы нужно добавить и удалить, что сделает переход элемента максимально плавным и автоматическим. Убедитесь, что вы используете простые классы CSS, которые не зависят от структуры вложенности DOM, чтобы элемент якоря выглядел так же, как исходный элемент (так как клонированный элемент размещается внутри корневого элемента, который, вероятно, близок к телу элемента).
Обратите внимание, что если корневой элемент находится на элементе <html>, то клонированный узел будет помещен внутрь тела.
Использование $animate в коде директивы
До сих пор мы изучали, как подавать анимации в приложение Angular, но как мы запускаем анимации внутри собственных директив в нашем приложении? Введя сервис $animate в наш код директивы, мы можем запускать структурные и основанные на классах крючки, которые затем могут быть использованы анимациями. Представьте, что у нас есть приветственный блок, который показывает и скрывает себя при изменении данных
<greeting-box active="onOrOff">Hi there</greeting-box>
ngModule.directive('greetingBox', ['$animate', function($animate) {
return function(scope, element, attrs) {
attrs.$observe('active', function(value) {
value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');
});
});
}]);
Теперь класс CSS on добавляется и удаляется в компоненте приветственного блока. Теперь, если мы добавим класс CSS поверх элемента приветственного блока в наш код HTML, мы можем запустить анимацию CSS или JS.
/* normally we would create a CSS class to reference on the element */
greeting-box.on { transition:0.5s linear all; background:green; color:white; }
Сервис $animate содержит множество других методов, таких как enter, leave, animate и setClass. Чтобы узнать больше о возможностях, посетите страницу API сервиса $animate.
Предотвращение конфликтов с сторонними библиотеками
Некоторые сторонние фреймворки устанавливают значения по умолчанию для длительности анимации для многих элементов или селекторов className, чтобы уменьшить размер своего кода и сделать его переиспользуемым. Это может привести к проблемам с ngAnimate, который ожидает фактических анимаций на этих элементах и должен ждать их завершения.
Вы можете предотвратить это нежелательное поведение, используя префикс для всех ваших анимационных классов:
/* prefixed with animate- */
.animate-fade-add.animate-fade-add-active {
transition:1s linear all;
opacity:0;
}
Затем вы настраиваете $animate для принудительного использования этого префикса:
$animateProvider.classNameFilter(/animate-/);
Это также может повысить скорость вашего приложения, так как только определенные элементы, содержащие префикс класса CSS, будут оцениваться для анимации при любых изменениях DOM в приложении.
Обратные вызовы и обещания
Когда вызывается $animate , возвращается обещание, которое может быть использовано для захвата момента окончания анимации. Таким образом, если мы собираемся запустить анимацию (внутри нашего кода директивы), мы можем продолжить выполнение деятельности, связанной с директивой и областью, после завершения анимации, объединяясь с возвращаемым обещанием, которое возвращает метод анимации.
// somewhere within the depths of the directive
$animate.enter(element, parent).then(function() {
//the animation has completed
});
(Обратите внимание, что в более ранних версиях Angular до версии 1.4 код обещания должен был быть обернут с помощью $scope.$apply(...). Это больше не требуется.)
В дополнение к обещанию анимации мы также можем использовать обратные вызовы, связанные с анимацией, в наших директивах и коде контроллера, зарегистрировав обработчик событий с помощью сервиса $animate. Например, предположим, что анимация была запущена в нашем контроллере маршрутизации представления, чтобы подключиться к этому:
ngModule.controller('HomePageController', ['$animate', function($animate) {
$animate.on('enter', ngViewElement, function(element) {
// the animation for this route has completed
}]);
}])
(Обратите внимание, что вам необходимо запустить переваривание в обратном вызове, чтобы заставить Angular заметить любые изменения, связанные с областью.)
Модульные компоненты
Директива
| Имя | Описание |
|---|---|
| ngAnimateChildren |
ngAnimateChildren позволяет указать, что дочерние элементы этого элемента должны анимироваться, даже если некоторые из родительских элементов детей в настоящее время анимированы. По умолчанию, когда у элемента есть активная |
Сервис
| Имя | Описание |
|---|---|
| $animateCss |
Сервис |
| $animate |
Документация сервиса ngAnimate |
© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.4.14/docs/api/ngAnimate