Spec-Zone.ru › Angular.js 1.6

Улучшить эту документацию 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, вы активируете анимационные крючки для приложения AngularJS.

Использование

Проще говоря, есть два способа использовать анимации с использованием 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, мы можем создать анимацию, которая будет обрабатываться AngularJS, когда связанная директива выполнит операцию.

В примере ниже показано, как можно реализовать анимацию 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.

Каскадные анимации 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;

  /* if you are using animations instead of transitions you should configure as follows:
    animation-delay: 0.1s;
    animation-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 AngularJS
      // 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 анимаций более гибким. Однако, в отличие от более ранних версий AngularJS, определение 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, чтобы увидеть, существует ли соответствие ссылки между компонентами в выходящем представлении и входящем. Он просканирует и удаляемое (выходящее), и вставляемое (входящее) представление, чтобы увидеть, есть ли сопоставленные 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 в вашем коде директивы

До сих пор мы рассматривали, как вводить анимации в приложение AngularJS, но как мы можем запускать анимации внутри собственных директив в нашем приложении? Введя сервис $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');
    });
  });
}]);

Теперь класс 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.

Обратные вызовы и обещания

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

// somewhere within the depths of the directive
$animate.enter(element, parent).then(function() {
  //the animation has completed
});

(Обратите внимание, что в более ранних версиях AngularJS до версии 1.4 код обещания необходимо было обернуть с помощью $scope.$apply(...) . Это больше не требуется.)

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

ngModule.controller('HomePageController', ['$animate', function($animate) {
  $animate.on('enter', ngViewElement, function(element) {
    // the animation for this route has completed
  }]);
}])

(Обратите внимание, что вам потребуется запустить переваривание в обратном вызове, чтобы AngularJS заметил любые изменения, связанные с областью видимости.)

Компоненты модуля

Директива

Имя Описание
ngAnimateChildren

ngAnimateChildren позволяет указать, что дочерние элементы этого элемента должны анимироваться, даже если один из родителей дочерних элементов анимируется в данный момент. По умолчанию, когда у элемента активная enter, leave, или move (структурная) анимация, дочерние элементы, у которых также активна структурная анимация, не анимируются.

ngAnimateSwap

ngAnimateSwap — это директива, ориентированная на анимацию, которая позволяет контейнеру удаляться и вставляться при изменении связанного выражения. Распространенный пример использования этой директивы — это компонент вращающегося баннера или слайдера, который содержит одно изображение в данный момент. Когда активное изображение изменяется, старое изображение выполнит анимацию leave , а новый элемент будет вставлен с помощью анимации enter .

Сервис

Имя Описание
$animateCss

Сервис $animateCss — это полезная утилита для запуска настраиваемых CSS-переходов/ключевых кадров из анимации на основе JavaScript или непосредственно из директивы. Цель $animateCss — НЕ обойти механизмы работы $animate и ngAnimate, но цель состоит в том, чтобы позволить существующим анимациям или директивам создавать более сложные анимации, которые могут быть чисто управляемы кодом CSS.

$animate

Документация сервиса $animate ngAnimate такая же, как и для основного сервиса $animate.

© 2010–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.6.9/docs/api/ngAnimate

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API