Angular开发者们!
当我同时使用ngAnimate和UI-Router时,遇到了一些问题。基本上,我的主要内容由五个子状态(“幻灯片”)和每一侧的一个按钮组成。点击这些按钮时,它们分别转到前一张和后一张幻灯片。
我使用CSS3转换来动画化幻灯片的进入和退出。当用户点击左边的按钮时,当前幻灯片向右退出,而“前一个”幻灯片从左侧进入。右侧按钮被单击时,情况相反:当前幻灯片向左退出,而“下一个”幻灯片从右侧进入。这些幻灯片循环播放,因此幻灯片零转到幻灯片四,反之亦然。
我的幻灯片进入和退出视口的方向(请记住,这些幻灯片是UI-Router状态,因此它们在动画结束时会从DOM中删除)由我应用于父元素的类决定。应用“left”类使幻灯片向左动画,反之亦然。
代码分为几个元素:
- appSlideDirective
- 指令,包含幻灯片按钮和一个嵌入式的UI-Router视图div(内容)
- 处理用户按钮按下事件并将点击事件传递给baseController进行状态转换
- baseController
- 属于父模块的控制器,管理stateService
- stateService(仅由baseController使用)
- 在指令发送事件时在UI-Router状态之间导航
- slideService(仅由指令使用)
- 通过ng-click管理'left'和'right'类的添加和删除
指令HTML:
<div id="slide-container">
<div id="slide" data-ng-class="{ left: slide.getTransitionState().left, right: slide.getTransitionState().right }">
<div id="slide-content" data-ui-view></div>
</div>
</div>
相关指令代码:
angular.module('app').directive('appSlide', function(slideService) {
restrict: 'A',
scope: {
currentState: '=',
numberOfStates: '=',
loadPreviousState: '&onPreviousState',
loadNextState: '&onNextState'
},
templateUrl: 'slide.html',
link: function(scope, element) {
scope.$on('$destroy', function() {
element.empty();
});
},
controller: function($scope, $timeout) {
var vm = this;
// ...
vm.loadPreviousSlide = function() {
slideService.preparePreviousSlide();
$scope.loadPreviousState();
});
vm.loadNextSlide = function() {
slideService.prepareNextSlide();
$scope.loadNextState();
});
vm.getTransitionState = function() {
return slideService.getTransitionState();
};
// ...
},
controllerAs: 'slide'
});
相关控制器代码:
angular.module('app').controller('baseController', function(stateService) {
var vm = this;
// ...
vm.loadPreviousState = function() {
stateService.loadPreviousState();
};
vm.loadNextState = function() {
stateService.loadNextState();
};
// ...
});
相关服务代码:
angular.module('app').factory('slideService', function() {
var _transitionState = {
left: false,
right: false
};
return {
preparePreviousSlide: function() {
_transitionState.right = false;
_transitionState.left = true;
},
prepareNextSlide: function() {
_transitionState.left = false;
_transitionState.right = true;
},
getTransitionState: function() {
return _transitionState;
}
// ...
};
});
angular.module('app').factory('stateService', function($state) {
// ...
return {
// ...
loadPreviousState: function() {
var targetState = _calculatePreviousState();
$state.go( targetState );
},
loadNextState: function() {
var targetState = _calculateNextState();
$state.go( targetState );
}
// ...
};
});
这个方法基本可行,但是在页面加载时,由于没有 'left' 类或 'right' 类存在,第一次幻灯片转换失败。同样地,切换方向(即向左两次,然后向右一次)会使幻灯片从错误的方向出现,因为上一个动画的 'left'/'right' 类仍然存在于元素上。
经过一些探索,我认为我已经发现了为什么第一次/相反的动画失败的原因:ng-click 事件开始了一个 digest 循环,阻止任何作用域更改发生,直到它的所有操作完成--这意味着状态在正确的 'left'/'right' 类被更新并且对应的 CSS3 变换样式可以被应用之前就已经被更改了。因此,在我正确更新了 'left' 和 'right' 类并且只有在另一个 digest 循环被运行之后才能更改状态。
我经历了许多代码迭代,我的当前实现依赖于 $scope.$apply 和 $timeout 服务。要强制进行另一个 digest 循环,我运行 $scope.$apply--我使用 $timeout 来防止 "in progress" 错误。然后当 $timeout promise 被解决时,我运行我的状态更改。
相对指令更新
vm.loadPreviousSlide = function() {
var promise = $timeout(function() {
$scope.$apply(function() {
slideService.preparePreviousSlide();
});
}, 0, false);
promise.then(function() {
$scope.loadPreviousState();
});
};
vm.loadNextSlide = function() {
var promise = $timeout(function() {
$scope.$apply(function() {
slideService.prepareNextSlide();
});
}, 0, false);
promise.then(function() {
$scope.loadNextState();
});
};
我对此有两个问题。首先,它冒犯了我的感官 - 它让我觉得比必要的复杂。其次,它 不是100%有效的。有时它有效,有时候不行。我不知道为什么会失败。
你们认为怎么样?如果您能想出更好的解决方案或者找出为什么我的解决方法偶尔会失败的原因,请告诉我!谢谢你们的时间。
哦,最后一件事 - 我对AngularJS相当新,请随时提供关于代码结构或方法的建议!
var promise = $scope.$evalAsync(function() { slideService.prepareNextSlide(); });
- Pankaj Parkar