【问题标题】:Google I/O 2015 page like transition animationsGoogle I/O 2015 页面类似过渡动画
【发布时间】:2015-09-11 22:34:20
【问题描述】:

最近我真的很喜欢Google I/O 2015 event page,尤其是那些不同状态之间的过渡动​​画。我知道他们为此使用了Polymer,但我正在尝试在 Angular (1.4.1) 和 Angular-material 和 ui-router 中重新创建这种延迟的动画。

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

  1. 在状态更改之前,为应用的离开组件设置动画
  2. 保留应用程序的一些基本结构(一些基本的容器容器)
  3. 进行状态更改 - 解析资源(REST API 调用)
  4. 过渡到具有基本应用结构(持有者)的新状态
  5. 动画进入元素(具有不同的延迟)

这不是一件小事,而且 ng-animate 也不是很有帮助,但我想使用的是尽可能多的。一个缺点是,在解决 Promise 之前没有添加离开的 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,但在任何动画发生之前等待 promise 被解析(加载器动画是必要的)

  2. angular-gsapify-router,使用了javascript动画,和上面的问题一样。

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

P.S.:很抱歉缺少图书馆的链接,但这是我第一次发帖,所以我只能发布 2 个链接:)

【问题讨论】:

  • 为了解决必须等待承诺得到解决的问题,为什么不尽快加载数据 - 更高的链。您甚至可以将数据拆分为初始转换所需的数据,然后再加载其余数据。为了以一种简单的方式做到这一点,我通常使用抽象父状态。作为您提到的两个库的作者,请随时在 Github 问题中向我提问。

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


【解决方案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);
    }
}

【讨论】:

  • 干得好!我正在考虑基于此为ui-view 指令创建一个装饰器,因此您可以指示其子元素在过渡时应进行动画处理。这与嵌套状态相结合,可能会导致一些非常酷的 UI。如果您有兴趣合作,请在 GitHub 上找到我。
猜你喜欢
  • 1970-01-01
  • 2015-12-11
  • 2017-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-23
  • 2018-08-09
  • 2017-10-29
相关资源
最近更新 更多