Google I / O 2015页面就像过渡动画一样

时间:2015-06-25 10:53:40

标签: angularjs animation angular-ui-router material-design angular-material

最近我非常喜欢Google I/O 2015 event page,特别是那些不同州之间的过渡动​​画。我知道他们使用了Polymer,但是我试图在Angular(1.4.1)和Angular-material和ui-router中重新创建这种延迟动画。

基本上我想要实现的是这个工作流程:

  1. 在状态更改之前,动画离开应用程序的组件
  2. 留下应用程序的一些基本结构(一些基本的持有者容器)
  3. 进行状态更改 - 解析资源(REST API调用)
  4. 转换到新状态,具有基本的应用程序结构(持有者)
  5. 动画输入元素(具有不同的延迟)
  6. 这不是一项微不足道的任务,ng-animate不是很有帮助,但我想尽可能多地使用它。一个缺点是,在保证解决之前不会添加css类,另一个缺点是,在某一时刻,新旧状态视图都出现在页面上。

    我试图创建这个指令:

    (function() {
        'use strict';
    
        angular
            .module('climbguide')
            .directive('cgAnimateElement', cgAnimateElement);
    
        /* @ngInject */
        function cgAnimateElement($animate, $rootScope, $state) {
            return {
                restrict:         'A',
                link:             linkFunc
            };
    
            function linkFunc(scope, el) {
                $animate.enter(el, el.parent());
    
                var cleanUp = $rootScope.$on('$stateChangeStart',
                    function(event, toState, toParams) {
                        if ($rootScope.stateChangeBypass) {
                            $rootScope.stateChangeBypass = false;
                            return;
                        }
                        event.preventDefault();
    
                        var promise = $animate.leave(el);
    
                        promise.then(function() {
                            $rootScope.stateChangeBypass = true;
                            $state.go(toState.name, toParams);
                        });
    
                    });
    
                scope.$on('$destroy', function() {
                    cleanUp();
                });
            }
        }
    
    })();
    

    它基本上做了我想要的,但由于某种原因它只能使用它一个元素 - 我假设因为$ rootScope。$ on(' $ stateChangeStart')以及后来使用$ state.go(toState.name,toParams);.

    我还找到了另外两个解决方案,

    1. angular-ui-router-in-out ,它使用CSS,但是等待promises在任何动画发生之前被解析(加载器动画是必要的)

    2. angular-gsapify-router ,它使用javascript动画,并且遇到与上面相同的问题。

    3. 我仍然只是学习角度,所以我真的不知道如何以正确的方式做到这一点。你有什么想法?非常感谢。

      P.S。:抱歉找不到图书馆的链接,但这是我发给SO的第一篇文章,所以我只能发布2个链接:)

1 个答案:

答案 0 :(得分:1)

也许它会对某些人有所帮助,但是我可以用它来处理脏兮兮的黑客攻击,但无论如何它确实如此,我在原帖中所描述的。

我更改了指令,因此可以多次重复使用:

(function() {
    'use strict';

    angular
        .module('climbguide')
        .directive('cgAnimateElement', cgAnimateElement);

    /* @ngInject */
    function cgAnimateElement($animate, delayedRouterService) {
        return {
            restrict: 'A',
            link:     linkFunc
        };

        function linkFunc(scope, el) {

            var stateChangeBypass = false;
            $animate.enter(el, el.parent());

            // Use scope instead of $rootScope, so there is no need to de-register listener
            scope.$on('$stateChangeStart',
                function(event, toState, toParams) {
                    if (stateChangeBypass) {
                        // Resuming transition to the next state broadcasts new $stateChangeStart
                        // event, so it necessary to bypass it
                        stateChangeBypass = false;
                        return;
                    }
                    delayedRouterService.holdStateChange(event);
                    var promise = $animate.leave(el);
                    promise.then(function() {
                        stateChangeBypass = true;
                        delayedRouterService.releaseStateChange(toState, toParams);
                    });
                });
        }

    }

})();

我创建了处理状态更改的服务 - 在ui-router中阻止和恢复状态更改:

(function() {
    'use strict';

    angular
        .module('climbguide')
        .factory('delayedRouterService', delayedRouterService);

    /* @ngInject */
    function delayedRouterService($state) {

        var _runningAnimations = 0;

        /**
         * Public methods
         *
         */
        var service = {
            holdStateChange:    holdStateChange,
            releaseStateChange: releaseStateChange
        };

        return service;
        //////////////

        /**
         * Prevent state change from the first animation
         * Store the number of currently running animations
         *
         * @param event
         */
        function holdStateChange(event) {
            if (_runningAnimations === 0) {
                event.preventDefault();
            }
            _runningAnimations++;
        }

        /**
         * Remove animation from the stack after it is finished
         * Resume state transition after last animation is finished
         *
         * @param toState
         * @param toParams
         */
        function releaseStateChange(toState, toParams) {
            _runningAnimations--;

            if (_runningAnimations === 0) {
                $state.go(toState.name, toParams);
            }
        }

    }
})();

因此可以在HTML中为我想要动画的元素使用它

<div class="main" cg-animate-element>
    ...
</div>

最终的CSS:

.main {
    &.ng-animate {
        transition: opacity, transform;
        transition-duration: 0.4s;
        transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
    }

    &.ng-enter {
        opacity: 0;
        transform: translate3d(0, 100px, 0);
    }

    &.ng-enter-active {
        opacity: 1;
        transform: translate3d(0, 0, 0);
    }

    &.ng-leave {
        opacity: 1;
        transform: translate3d(0, 0, 0);
    }

    &.ng-leave-active {
        opacity: 0;
        transform: translate3d(0, 100px, 0);
    }
}