AngularJS摘要周期偶尔无法更新范围

时间:2015-03-08 10:28:11

标签: javascript angularjs angularjs-scope angular-ui-router ng-animate

Angular Devs!

在使用ngAnimate和UI-Router时,我遇到了一些问题。基本上,我有五个子状态("幻灯片")构成我的主要内容以及每一侧的按钮。单击时,这些按钮分别转到上一张和下一张幻灯片。

我使用CSS3翻译动画幻灯片的进入和退出。当用户单击左按钮时,当前幻灯片退出到右边并且" previous"幻灯片从左侧进入。单击右键时,情况正好相反:当前幻灯片向左退出," next"幻灯片从右侧进入。这些幻灯片循环播放,因此幻灯片零转到四个幻灯片,反之亦然。

我的幻灯片进入和退出视口的方向(请记住幻灯片是UI-Router状态,因此它们在动画结束时从DOM中删除)由我应用于父级的类确定元件。应用"左" class使幻灯片向左动画,而#34; right#34;类。

代码分为几个部分:

  • appSlideDirective
    • 包含幻灯片按钮和嵌入式UI-Router视图div(内容)
    • 的指令
    • 处理用户按钮按下并将click事件传递给baseController以进行状态转换
  • baseController
    • 属于父模块的控制器,管理stateService
  • stateService(仅由baseController使用)
    • 在指令发送事件
    • 时在UI路由器状态之间导航
  • slideService(仅供指令使用)
    • 管理'离开'并且'对'类添加和删除(通过ng-click)

指令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 );
        }

        // ...
    };
});

这在大多数情况下运作得相当好。第一张幻灯片转换无法在页面加载时设置动画,因为“左”和“离开”都没有。班级也没有“权利”。上课。类似地,切换方向(即向左移动两次,然后向右移动一次)使得幻灯片从错误的一侧出现,因为前一个动画的左侧&#39;右侧&#39; class仍然在元素上。

经过一番挖掘后,我想我偶然发现了第一个/相反动画失败的原因:ng-click事件启动一个摘要周期,阻止任何范围变化发生,直到所有动作完成后 - - 意味着在正确的“左”和“右”之前改变了状态。 class是和它相应的CSS3变换样式可以应用。因此,一旦我正确更新了“左”,我需要运行另一个摘要周期。并且&#39;对&#39;类,然后才改变状态。

我经历了很多代码迭代,我当前的实现依赖于$ scope。$ apply和$ timeout服务。为了强制另一个摘要周期,我运行$ scope。$ apply - 我使用$ timeout来防止&#34;正在进行中#34;错误。然后,当$ timeout声明得到解决时,我会运行状态更改。

相对指令更新

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很新,所以请随时提供有关代码结构或方法的建议!

1 个答案:

答案 0 :(得分:0)

几个月前我解决了这个问题。

我被迫实施一种明显不那么“角度”的解决方案,但是100%的时间都在工作。

长话短说,我最终手动添加和删除类,而不是等待下一个摘要周期。

例如:

var slide = angular.element(document.querySelector('#slide'));
slide.removeClass('right');
slide.addClass('left');

然后触发适当的状态转换是微不足道的。