Подтвердить что ты не робот

Две разные анимации для изменения маршрута

У меня есть следующий случай: я использую ui-router для маршрутизации в моем приложении AngularJS. В одном маршруте существует пять дочерних состояний для разных подэкранов. Я хочу анимировать переход между ними карусельным образом.

Навигация выглядит следующим образом:

Link to A | Link to B | Link to C | Link to D | Link to E

Перемещение с state A на state B должно сделать screen A сдвигом влево и screen B сдвинуть справа; наоборот, для перехода от state B до state A.

Работает ли анимация переходов на экране с помощью transform: translateX(...); на enter и leave только в одном направлении.

Обычно я управляю анимацией, используя ng-class с флагом. В этом случае, однако, установка класса в элементе ui-view вообще не работает (Angular 1.2 и ui-router 0.2 еще не полностью совместимы). Он также не работает с настройкой его с помощью настраиваемой директивы, прослушивающей scope.$on "$stateChangeStart", которая запускается после начала перехода.

Как я могу реализовать желаемое поведение?

Изменить: решение

Для записи: я закончил ее реализацию, используя пользовательскую функцию $scope, используя $state.go(), чтобы определить направление перед изменением маршрута. Это позволяет избежать ошибок $digest already in progress. Класс, определяющий анимацию, добавляется в родительский элемент ui-view; это оживляет как текущее, так и будущее ui-view в правильном направлении.

Функция контроллера (Coffeescript):

go: (entry) ->
  fromIdx = ...
  toIdx = ...

  if fromIdx > toIdx
    $scope.back = false
  else
    $scope.back = true

  $state.go entry

Шаблон:

<div ng-class="{toLeft: back}">
  <div ui-view></div>
</div>
4b9b3361

Ответ 1

Вы можете управлять классами в своем представлении, настроив контроллер специально для этого. Затем вы можете подписаться на события в приложении и изменить способ анимации страницы.

<div class="viewWrap" ng-controller="viewCtrl">
  <div class="container" ui-view ng-class="{back: back}"></div>
</div>

Затем в вашем контроллере

.controller('viewCtrl', function ($scope) {
    $scope.$on('$stateChangeSuccess', function (event, toState) {
        if (toState.name === 'state1') {
            $scope.back = true; 
        } else {
            $scope.back = false; 
        }
    });
});

Я создал код, чтобы продемонстрировать здесь http://codepen.io/ed_conolly/pen/aubKf

Для любого, кто пытается это сделать, обратите внимание, что мне пришлось использовать модуль ui.router.compat из-за текущей несовместимости анимаций в Angular 1.2 и UI Router.

Ответ 2

Вы всегда можете проверить ветвь angular -1.2: https://github.com/angular-ui/ui-router/tree/angular-1.2. Это исправляет ngAnimate вместе с несколькими другими вещами.

Я полагаю, что это будет включено в ui-router 0.3.0, так что пока вы не будете нажимать вживую в ближайшее время, это должно предоставить вам необходимую вам функцию, пока вы не сможете вернуться на "стабильную" ветвь.

Отказ от ответственности: у меня нет полномочий, когда следующая версия UI-маршрутизатора будет или что она будет включать. Я просто нашел эту информацию в различных вопросах на странице github.

Ответ 3

Решение Eddiec было действительно приятным началом, но я все же немного взломал его. Вот измененный контроллер, который работает лучше для моих целей. Это более динамично:

function ViewCtrl($scope, $state) {

   $scope.$on('$stateChangeStart', function (event, toState) {
        var movingToParent = $state.includes(toState.name);
        if (movingToParent) {
            $scope.back = true; 
        } else {
            $scope.back = false; 
        }
    });


}

Ответ 4

Я пытался сделать то же самое с ngRoute с помощью $routeChangeSuccess, но проблема, с которой я столкнулся, заключалась в том, что анимация ng-leave начнется до запуска цикла дайджест. Анимация ввода всегда была правильной, но анимация останова всегда была предыдущей.

Решение, которое работало для меня (Angular 1.57), состояло в том, чтобы обернуть вызов $location.path() в $timeout. Это гарантирует, что полный дайджест будет запущен до начала анимации.

function goto(path) {
    if(nextIndex > currentIndex) {
      ctrl.transition = 'slide-out-left';
    } else {
      ctrl.transition = 'slide-out-right';
    }
    $timeout(function() {
      $location.path(path);
    });
  }

Ответ 5

Аналогичная попытка принять @eddiec ответ. В основном массив значений имени состояния, а затем позиция в массиве имен значений toState и fromState сравниваются для определения направления.

.controller('viewCtrl', function ($scope) { 
    $scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {

        // create an array of state names, in the order they will appear
        var states = ['state1', 'state2', 'state3'];

        if (states.indexOf(toState.name) < states.indexOf(fromState.name)) {
          $scope.back = true; 
        } 
        else {
         $scope.back = false;  
        }
    });
});

Codepen, раздвоенный сверху, показывая рабочий результат. http://codepen.io/anon/pen/zBQERW