Две разные анимации для изменения маршрута
У меня есть следующий случай: я использую 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>
Ответы
Ответ 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