AngularJS: Директива: Анимировать скользящие страницы и отложить привязку контроллера

Я пытаюсь выяснить, как отложить привязку контроллера по умолчанию и применить его только изнутри директивы, как только определенная анимация (custom - не 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 ответ

Прежде всего, некоторые минимальные изменения, чтобы получить то, что у вас работает. Вам нужно запретить навигацию по странице по умолчанию (поэтому она изменяется до завершения навигации), и вам нужно выполнить навигацию вручную после завершения первой анимации. Таким образом, один из способов состоит в том, чтобы передать событие и URL в 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 элемент, помечая элемент для анимации другой директивой. Однако применяется тот же основной принцип: остановить распространение события, выполнить первую анимацию, а затем обновить местоположение перед выполнением второй анимации.

Другие вопросы по тегам