Условная анимация переходов ng-view

Я пытаюсь применить анимацию к ng-view (маршрутизации) в зависимости от задействованных представлений.

Например, из View1 в View2 мне нужно, чтобы View1 выходил через левую сторону, а View1 входил с правой стороны. В противном случае из View2 в View1 мне нужно, чтобы View2 выходил через правую сторону, а View1 входил с левой стороны.

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

Что я делаю, так это использую связанную с областью переменную в качестве класса в ng-view:

<div ng-view class="{{transition}}"></div>

Эта переменная устанавливается при каждом изменении маршрута примерно так в каждом контроллере:

$scope.transition=Global.transition;

$rootScope.$on("$routeChangeStart",function (event, current, previous) {
   // Here I get the leaving view and the entering view and the kind of transition is selected
   ...
   $scope.transition=selectedLeavingTransition;  // Set the transition for the leaving view
   Global.transition=selectedEnteringTransition; // Set the transition for the entering view
});

Global — это сервис для установки переменной перехода для входящей области видимости из области выхода.

Таким образом, при обнаружении изменения маршрута текущее представление ng устанавливается с классом, связанным с selectedLeavingTransition, а входящее представление ng устанавливается с классом, связанным с selectedEnteringTransition.

Например, если изменение маршрута было с View1 на View2, ng-views во время анимации могут быть:

<div ng-view class="fadeOut ng-animate ng-leave ng-leave-active"></div>
<div ng-view class="scaleUp ng-animate ng-enter ng-enter-active"></div>

CSS в этом случае может быть:

fadeOut.ng-leave {animation:1s fadeOut;}
scaleUp.ng-enter {animation:1s scaleUp;}

Хотя это работает, мне интересно, есть ли более простой способ сделать это, поскольку это кажется небольшим беспорядком.


person IsidroGH    schedule 31.03.2014    source источник


Ответы (2)


Альтернативное решение, не требующее большого количества кода, состоит в том, чтобы определить ваши анимации на ваших маршрутах:

$routeProvider.when('/view1', {
  templateUrl: 'view1.html',
  controller: 'View1Controller',
  animations: {
    enter: 'enter-left',
    leave: 'leave-left'
  }
});

Затем используйте директиву для получения анимаций текущего маршрута и добавления их к элементу:

app.directive('viewAnimations', function ($route) {
  return {
    restrict: 'A',
    link: function (scope, element) {
      var animations = $route.current.animations;
      if (!animations) return;

      if (animations.enter) element.addClass(animations.enter);
      if (animations.leave) element.addClass(animations.leave);
    }
  };
});

И поместите директиву в элемент, содержащий директиву ngView:

<body ng-view view-animations></body>

Демо: http://plnkr.co/edit/Y3ExDyiPIJwvVKO4njBT?p=preview.

Изменить: новое решение.

Чтобы установить анимацию во время выполнения, я бы использовал службу, как и вы, но директиву для их применения.

Очень простой пример сервиса:

app.factory('viewAnimationsService', function ($rootScope) {

  var enterAnimation;

  var getEnterAnimation = function () {
    return enterAnimation;
  };

  var setEnterAnimation = function (animation) {
    enterAnimation = animation;
  };

  var setLeaveAnimation = function (animation) {
    $rootScope.$emit('event:newLeaveAnimation', animation);
  };

  return {
    getEnterAnimation: getEnterAnimation,
    setEnterAnimation: setEnterAnimation,
    setLeaveAnimation: setLeaveAnimation
  };
});

И директива:

app.directive('viewAnimations', function (viewAnimationsService, $rootScope) {
  return {
    restrict: 'A',
    link: function (scope, element) {

      var previousEnter, previousLeave;

      var enterAnimation = viewAnimationsService.getEnterAnimation();
      if (enterAnimation) {
        if (previousEnter) element.removeClass(previousEnter);
        previousEnter = enterAnimation;
        element.addClass(enterAnimation);
      }

      $rootScope.$on('event:newLeaveAnimation', function (event, leaveAnimation) {
        if (previousLeave) element.removeClass(previousLeave);
        previousLeave = leaveAnimation;
        element.addClass(leaveAnimation);
      });
    }
  };
});

Демо: http://plnkr.co/edit/DuQXaN2eYgtZ725Zqzeu?p=preview

person tasseKATT    schedule 09.04.2014
comment
Хорошее решение с использованием директивы, хотя в моем случае переходы выхода и входа выбираются во время выполнения на основе текущего и следующего представления, поэтому я не могу определить их статически в маршруте. - person IsidroGH; 09.04.2014
comment
Ах я вижу. Это решение все еще можно использовать с небольшим количеством дополнительного кода. Я отредактирую свой ответ позже, когда у меня будет время. - person tasseKATT; 09.04.2014

Я работал над этим, и у меня есть более аккуратное решение, то, что я делал, имело некоторые проблемы. Теперь я просто использую $routeChangeStart в корневой области и выбираю переходы выхода и входа.

Единственная проблема, с которой я столкнулся, заключается в том, что в событии routeChangeStart я не могу изменить выходное представление, поэтому я не могу установить выходной переход к атрибуту класса элемента ngView. Мне пришлось установить его напрямую через DOM (я знаю, что это плохая практика).

Я пытался изменить выходной вид через общий сервис, корневую область и $apply(), но ни один из них не работал. После запуска события routeChangeStart представление кажется статичным.

Вот рабочий пример: jsfiddle.net/isidrogarcia/Fs5NZ.

person IsidroGH    schedule 01.04.2014