Улучшить эту документацию ngAnimate
Установка
Сначала получите файл:
- Google CDN например
"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-animate.js"
- NPM например
npm install --save angular-animate@X.Y.Z
илиyarn add angular-animate@X.Y.Z
- 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-animate.js в свой HTML:
<script src="path/to/angular.js"></script> <script src="path/to/angular-animate.js"></script>
Наконец, загрузите модуль в ваше приложение, добавив его как зависимый модуль:
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 | добавление и удаление (грязный, чистый, валидный, невалидный и все другие валидации) |
| 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, мы помещаем анимацию в класс .ng-hide CSS:
<div ng-show="bool" class="fade">
Show and hide me
</div>
<button ng-click="bool=!bool">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-классу, используемому для анимации. Свойство стиля, ожидаемое в классе задержки, может быть свойством 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);
}
}
}]);
Преимущество анимаций на основе JavaScript заключается в том, что мы можем вводить другие службы и использовать расширенные библиотеки анимаций, такие как 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.
Якорение анимации (через 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, чтобы проверить, есть ли соответствие ссылки между компонентами в покидаемом представлении и входящем представлении. Он будет сканировать как удаляемое (exit), так и вставляемое (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 или JavaScript.
/* 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.
Обратные вызовы и обещания
Когда вызывается $animate, он возвращает обещание, которое можно использовать для захвата момента окончания анимации. Следовательно, если мы запускаем анимацию (в коде нашей директивы), мы можем продолжить выполнение связанных с директивой и областью действий после завершения анимации, подключившись к возвращённому обещанию, которое возвращает метод анимации.
// somewhere within the depths of the directive
$animate.enter(element, parent).then(function() {
//the animation has completed
});
(Обратите внимание, что в более ранних версиях Angular до v1.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 позволяет указать, что дочерние элементы этого элемента должны анимироваться, даже если какие-либо из родителей детей в данный момент анимируются. По умолчанию, когда у элемента есть активная |
| ngAnimateSwap |
ngAnimateSwap — это директива, ориентированная на анимацию, которая позволяет контейнеру удаляться и вставляться всякий раз, когда связанное выражение изменяется. Общее использование этой директивы — компонент вращающегося баннера или слайдера, который содержит одно изображение в данный момент. Когда активное изображение изменяется, старое изображение выполнит |
Сервис
| Имя | Описание |
|---|---|
| $animateCss |
Сервис |
| $animate |
Документация сервиса ngAnimate |
© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.5.11/docs/api/ngAnimate