次のような場合があります。AngularJSアプリケーションのルーティングにui-routerを使用しています。 1つのルートでは、異なる従属画面に5つの子状態があります。これらの間の遷移をカルーセルのようにアニメーション化したいと思います。
ナビゲーションは次のようになります。
_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
_に移動する場合はその逆です。
動作するのは、enter
のtransform: translateX(...);
とoneのleave
で画面遷移をアニメーション化することです。方向のみ。
通常、私は_ng-class
_とフラグを使用してアニメーションを制御します。ただし、この場合、_ui-view
_要素にクラスを設定することはまったく機能しません(Angular1.2とui-router0.2はまだ完全には互換性がありません)。また、遷移の開始後に起動される_scope.$on "$stateChangeStart"
_をリッスンするカスタムディレクティブを使用して設定することもできません。
どうすれば目的の動作を実装できますか?
編集:ソリューション
ちなみに、ルートを変更する前に、$state.go()
を使用してカスタム_$scope
_関数を使用して方向を決定し、実装することになりました。これにより、_$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>
_
特にそれを行うようにコントローラーを設定することにより、ビュー上のクラスを制御できます。その後、アプリ内のイベントをサブスクライブして、ページのアニメーション方法を変更できます。
<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
これを行おうとしている人は、Angular 1.2とUIルーターのアニメーションの現在の非互換性のために、ui.router.compatモジュールを使用する必要があることに注意してください。
いつでもangular-1.2ブランチをチェックアウトできます: https://github.com/angular-ui/ui-router/tree/angular-1.2 。これにより、ngAnimateが他のいくつかの問題とともに修正されます。
これはui-router0.3.0に含まれると思います。すぐにライブをプッシュしない限り、「stable」ブランチに戻るまで必要な機能を提供するはずです。
免責事項:UIルーターの次のリリースがいつになるか、または何が含まれるかについては、私には権限がありません。私はこの情報をgithubページのさまざまな問題で見つけました。
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;
}
});
}
_$routeChangeSuccess
_を使用してngRoute
でこれと同じことを行おうとしましたが、遭遇した問題は、ダイジェストサイクルが実行される前に_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);
});
}
_
@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