AngularJS:指令:动画滑动页面并推迟控制器绑定

时间:2013-08-04 14:51:26

标签: jquery angularjs angularjs-directive angularjs-animation

我试图弄清楚如何推迟默认控制器绑定并仅在指令中应用它,一旦特定动画(自定义 - 而不是angularjs)已经对包含内容的DOM元素执行。我想要完成的事情就在这里,虽然它确实在滑动动画完成之前立即取代了内容:http://jsfiddle.net/scabro/hHy7s/27/

我需要能够推迟$ scope绑定,直到页面容器完成滑动/动画,然后用控制器内的数据替换内容,一旦完成,请向下滑动。

以下是我目前的情况:

HTML:

<div id="wrapper" ng-app="myApp">

    <div page-animate>

        <p>
            <a class="btn btn-primary" href="#/" ng-click="slidePage()">Home</a>
            <a class="btn btn-info" href="#/users" ng-click="slidePage()">Users</a>
            <a class="btn btn-success" href="#/pages" ng-click="slidePage()">Pages</a>
        </p>
        <div id="relativeContainer">

            <div id="content" ng-view=""></div>

        </div>

    </div>

</div>

CSS:

#wrapper {
    text-align:center;
    padding:30px 0;
}
#relativeContainer {
    text-align:left;
    position: relative;
    width: 500px;
    height: 800px;
    min-height: 800px;
    margin: 0 auto;
    overflow: hidden;
}
#content {
    position: absolute;
    top: 0;
    left: 0;
}

JS:

var myApp = angular.module('myApp', []);

myApp.directive('pageAnimate', function() {

    return {

        restrict: 'A',

        scope: { },

        link: function (scope, elem, attrs) {

            scope.slidePage = function() {

                var thisContainer = $('#content');

                var thisHeight = thisContainer.outerHeight();

                thisContainer.animate({ top : '-' + thisHeight + 'px'}, { duration : 300, complete : function() {

                    thisContainer.css({ top : '-999999em' });

                    var thisNewHeight = thisContainer.outerHeight();

                    $('#relativeContainer').animate({ height : thisNewHeight + 'px' }, { duration : 200, complete : function() {

                        thisContainer.css({ top : '-' + thisNewHeight + 'px' }).animate({ top : 0 }, { duration : 300 });

                    }});

                }});

            };

        }

    }

});


myApp.config(function($routeProvider) {

    $routeProvider
        .when('/',
            {
                controller: 'HomeController',
                template: '<h1>{{ heading }}</h1><p>{{ content }}</p>'
            }
        )
        .when('/users',
            {
                controller: 'UserController',
                template: '<h1>{{ heading }}</h1><p>{{ content }}</p>'
            }
        )
        .when('/pages',
            {
                controller: 'PageController',
                template: '<h1>{{ heading }}</h1><p>{{ content }}</p>'
            }
        )
        .otherwise(
            {
                redirectTo: '/'
            }
        )

});

myApp.controller('HomeController', function($scope) {

    $scope.heading = 'Home page';
    $scope.content = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate';

});

myApp.controller('UserController', function($scope) {

    $scope.heading = 'Users';
    $scope.content = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.';

});

myApp.controller('PageController', function($scope) {

    $scope.heading = 'Pages';
    $scope.content = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.';

});

1 个答案:

答案 0 :(得分:2)

首先,进行一些微小的改动以获得你的工作。您需要阻止默认事件导航页面(这就是导航完成之前更改的原因),并且您需要在第一个动画完成后手动执行导航。因此,一种方法是将事件和网址传递到slidePage

<div id="wrapper" ng-app="myApp">
    <div page-animate>
        <p>
            <a class="btn btn-primary"  ng-click="slidePage($event, '/')">Home</a>
            <a class="btn btn-info" ng-click="slidePage($event, '/users')">Users</a>
            <a class="btn btn-success" ng-click="slidePage($event, '#/pages')">Pages</a>
        </p>
        <div id="relativeContainer">

            <div id="content" ng-view=""></div>
        </div>
    </div>
</div>

slidePage本身变为:

        scope.slidePage = function(event, url) {
            event.preventDefault();
            event.stopPropagation();
            var thisContainer = $('#content');

            var thisHeight = thisContainer.outerHeight();

            thisContainer.animate({ top : '-' + thisHeight + 'px'}, { duration : 300, complete : function() {
                thisContainer.css({ top : '-999999em' });
                $location.url(url);
                scope.$apply();

                var thisNewHeight = thisContainer.outerHeight();

                $('#relativeContainer').animate({ height : thisNewHeight + 'px' }, { duration : 200, complete : function() {

                    thisContainer.css({ top : '-' + thisNewHeight + 'px' }).animate({ top : 0 }, { duration : 300 });

                }});

            }});

该代码应该按照您的意愿工作,但我认为它不符合角度哲学。

相反我认为你应该做的是直接添加slidePage指令,以便链接为<a href='#/pages' slide-page>。该指令可以访问属性(因此它可以获取href),并且可以将click处理程序直接绑定到锚元素上。我还会通过用另一个指令标记要动画的元素来删除#content元素的硬连线。但是,相同的基本原则适用:停止事件传播,执行第一个动画,然后在执行第二个动画之前更新位置。