【问题标题】:Alternative approach to ui-router state transition animationsui-router 状态转换动画的替代方法
【发布时间】:2014-04-23 07:07:56
【问题描述】:

我的产品负责人给了我一个我认为几乎不可能完成的任务,即在状态之间创建一些动画。我开始使用 ngAnimate 并想出了一个我认为很酷的解决方案来解决他的问题——错了。

“这不是他告诉我的。”

所以把它勾勒得更好一点。当我在折叠小部件的面板之间进行更改时,我也想更改状态并更新 URL。

那么,我还能如何使用类似手风琴的方法或引导术语 - 折叠小部件为状态转换设置动画?

【问题讨论】:

    标签: javascript angularjs animation angularjs-directive angular-ui-router


    【解决方案1】:

    好的...回到绘图板上,我想出了这个很酷的方法,尽管我可能会与任何感兴趣的人分享。

    首先让我们设置我们需要转换的状态。我只会用两个折叠面板而不是我拥有的三个来展示这个......无论如何它都会有很多代码,但值得分享的解决方案。

    路由 app.js

            .state('home.checkout', {
                url: 'checkout',
                views: {
                    '@home': {
                        templateUrl: 'views/partials/generic/checkout-process/order-checkout-root.html'
                    }
                }
            })
    
            .state('home.checkout.shoppingcart', {
                url: '^/shoppingcart',
                views: {
                    'shopping-cart@home.checkout': {
                        templateUrl: 'views/partials/generic/checkout-process/shoppingcart/shopping-cart-partial.html',
                        controller: 'ShoppingCartController'
                    },
                    'order-confirmation@home.checkout' : {
                        templateUrl: 'views/partials/generic/checkout-process/closed-state.html',
                        controller: function($scope) {
                            $scope.page = {name: 'Order Confirmation'};
                            $scope.state = {name: 'home.checkout.confirm'};
                        }
                    }
                }
            })
    
            .state('home.checkout.confirm', {
                url: '/confirmation',
                views: {
                    'shopping-cart@home.checkout': {
                        templateUrl: 'views/partials/generic/checkout-process/closed-state.html',
                        controller: function($scope) {
                            $scope.page = {name: 'Shopping Cart'};
                            $scope.state = {name: 'home.checkout.shoppingcart'};
                        }
                    },
                    'order-confirmation@home.checkout': {
                        templateUrl: '../views/partials/generic/checkout-process/confirmation/order-confirmation-partial.html',
                        controller: 'OrderConfirmationController'
                    }
                }
            })
    

    HTML order-checkout-root.html

    <div class="row checkout-process">
        <section class="col-sm-8 col-md-8 col-lg-8 panel-group" id="accordion">
            <div class="shopping-cart panel panel-default" ui-view="shopping-cart" autoscroll="false"></div>
            <div class="order-confirmation panel panel-default" ui-view="order-confirmation" autoscroll="false"></div>
        </section>
    </div>
    

    关闭状态.html

    <article class="col-sm-12 col-md-12 col-lg-12 panel-heading closed-state">
        <h4 class="panel-title">
            <a ui-sref="{{state.name}}">
                {{page.name}}
            </a>
        </h4>
    </article>
    

    order-confirmation-partial.html

    我将只包括这个,而不是另一个部分,因为它的想法相同。

    <div class="order-confirmation-page row">
        <div class="panel-heading">
            <h4 class="panel-title">Order Confirmation</h4>
        </div>
    
        <div class="panel-collapse collapse" kx-collapse-toggler data-toggle="collapse">
            <div class="panel-body">
                <!--Code for the collapse body goes here-->
            </div>
        </div>
    </div>
    

    最后一部分重要的是要注意指令的包含

    kx-collapse-toggler
    

    这是我们工作的地方,也是代码中最有趣的部分

    collapseTogglerDirective.js

    'use strict';
    
    angular.module('App.Directives.CollapseToggler', [])
    
        .directive('kxCollapseToggler', function ($rootScope, $state, $q, $timeout) {
    
            var linker = function(scope, element) {
    
                var
                    collapse = $q.defer(),
                    changeEventStarted = false
                ;
    
                //Expand the panel on directive instantiation
                $timeout(function() {
                    $(element).collapse('show');
                }, 300);
    
    
                $rootScope.$on('$stateChangeStart', function(event, toState) {
                    //Check to make sure we arent in the middle of a $stateChangeEvent
                    if(changeEventStarted) {
                        return;
                    }
                    //Stop the state transition
                    event.preventDefault();
    
                    //Collapse the panel
                    $(element).collapse('hide');
    
                    //Wait for the panel to collapse completely
                    collapse.promise.then(function() {
                        changeEventStarted = true;
                        //Then transiton the state
                        $state.transitionTo(toState);
                    });
                });
    
                //Event listener for the collapse completed
                $(element).on('hidden.bs.collapse', function() {
                    collapse.resolve();
                });
            };
    
            return {
                restrict: 'A',
                link: linker
            };
        });
    

    简而言之,我们在这里所做的是:

    1. 设置一个承诺,以了解我们何时可以再次过渡。
    2. 拦截 $stateChangeStart 事件并阻止它发生。
    3. 然后我们折叠我们感兴趣的面板
    4. 当折叠完成时,引导程序会触发一个事件,说我已经完成折叠,我们会监听它并依次解决承诺
    5. promise 解决后,我们可以安全地转换到下​​一个状态

    我希望这不会太多,但如果你做到了,它对其他类型动画的潜力是相当大的。

    我正在组装一个 plunker,以便可以看到动画。

    【讨论】:

    • 请问您为什么不使用 Angular ui 路由器模块的 onEnter/onExit 方法?
    • 据我所见,这些是位于路线中的方法 - 但我将使用它们来进行 DOM 操作,这是指令的工作。但也许你有更好的主意! :-)
    • 你确实做得很好,我告诉你只是为了给你一个简单的快速方法:)
    • 我很感激!但我不确定这是否是代码的正确位置。但是谢谢你给我看!我不知道这些方法存在!我相信它们会派上用场...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 2021-07-01
    • 1970-01-01
    相关资源
    最近更新 更多