admin管理员组

文章数量:1415467

I have the following AngularJS (v1.1.4) code and am trying to fade-in (animate) the ng-include when it is added to the DOM. What am I doing wrong? Also, if anyone can suggest a better way of passing add/set/remove mands to the directive rather than watching the 'action' property, that would be much appreciated.

Plunker is here:

index.html

<!doctype html>
<html ng-app="plunker" >
<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <link rel="stylesheet" href="styles.css" />
  <script>document.write('<base href="' + document.location + '" />');</script>
  <script src=".1.4/angular.js"></script>
  <script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">

  <button ng-click="loadPartial('partial1.html')">Click to load partial 1</button>
  <button ng-click="loadPartial('partial2.html')">Click to load partial 2</button>
  <button ng-click="loadPartial('partial3.html')">Click to load partial 3</button>

  <div views></div>

</body>
</html>

app.js

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

app.controller('MainCtrl', ['$scope', 'viewsAPI', function(scope, viewsAPI) {

  scope.loadPartial = function (name) {
    viewsAPI.addView(name);
  };

}]);


app.factory('viewsAPI', function () {

    return {
        views: [],
        action: null,
        addView: function (viewName, options) {
            var view = { name: viewName, options: options };
            this.action = { type: 'add', view: view };
        },
        setView: function (viewName, options) {
            var view = { name: viewName, options: options };
            this.action = { type: 'set', view: view };
        },
        removeView: function () {
            this.action = { type: 'remove' };
        }
    }
});


app.directive('views', ['$pile', function (pile) {

    return {
        restrict: 'A',
        scope: {},
        replace: true,
        template: '<div class="views"></div>',

        controller: ['$scope', 'viewsAPI', function (scope, viewsAPI) {

            scope.api = viewsAPI;

            scope.$watch('api.action', actionChange, true);

            function actionChange (action) {

                if (!action) return;

                if (action.type == 'add') {
                    var view = scope.addView(action.view);
                    scope.api.views.push(view);
                }
                else if (action.type == 'set') {
                    scope.setView(action.view);
                }
                else if (action.type == 'remove') {
                    scope.removeView();
                }
            }
        }],

        link: function (scope, elm) {

            scope.addView = function (view) {
                var v = pile('<div class="view-wrapper" ng-include="\'' + view.name + '\'" ng-animate="fade"></div>')(scope);
                elm.append(v);
                return v;
            };

            scope.setView = function (view) {
            };

            scope.removeView = function () {
            };
        }
    };
}]);

styles.css

.fade-enter-setup { -webkit-transition: all 3s linear; opacity: 0; }
.fade-enter-setup { opacity: 1; }

partial1.html

<div>Hello I am a partial 1</div>

partial2.html

<div>PARTIAL 2-------------------</div>

partial3.html

<div>
33333333333333333333333333
<br />
this is partial 3
<br />
33333333333333333333333333
</div>

I have the following AngularJS (v1.1.4) code and am trying to fade-in (animate) the ng-include when it is added to the DOM. What am I doing wrong? Also, if anyone can suggest a better way of passing add/set/remove mands to the directive rather than watching the 'action' property, that would be much appreciated.

Plunker is here: http://plnkr.co/edit/rcgpI0n8fGWj6o01Mp3b?p=preview

index.html

<!doctype html>
<html ng-app="plunker" >
<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <link rel="stylesheet" href="styles.css" />
  <script>document.write('<base href="' + document.location + '" />');</script>
  <script src="http://code.angularjs/1.1.4/angular.js"></script>
  <script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">

  <button ng-click="loadPartial('partial1.html')">Click to load partial 1</button>
  <button ng-click="loadPartial('partial2.html')">Click to load partial 2</button>
  <button ng-click="loadPartial('partial3.html')">Click to load partial 3</button>

  <div views></div>

</body>
</html>

app.js

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

app.controller('MainCtrl', ['$scope', 'viewsAPI', function(scope, viewsAPI) {

  scope.loadPartial = function (name) {
    viewsAPI.addView(name);
  };

}]);


app.factory('viewsAPI', function () {

    return {
        views: [],
        action: null,
        addView: function (viewName, options) {
            var view = { name: viewName, options: options };
            this.action = { type: 'add', view: view };
        },
        setView: function (viewName, options) {
            var view = { name: viewName, options: options };
            this.action = { type: 'set', view: view };
        },
        removeView: function () {
            this.action = { type: 'remove' };
        }
    }
});


app.directive('views', ['$pile', function (pile) {

    return {
        restrict: 'A',
        scope: {},
        replace: true,
        template: '<div class="views"></div>',

        controller: ['$scope', 'viewsAPI', function (scope, viewsAPI) {

            scope.api = viewsAPI;

            scope.$watch('api.action', actionChange, true);

            function actionChange (action) {

                if (!action) return;

                if (action.type == 'add') {
                    var view = scope.addView(action.view);
                    scope.api.views.push(view);
                }
                else if (action.type == 'set') {
                    scope.setView(action.view);
                }
                else if (action.type == 'remove') {
                    scope.removeView();
                }
            }
        }],

        link: function (scope, elm) {

            scope.addView = function (view) {
                var v = pile('<div class="view-wrapper" ng-include="\'' + view.name + '\'" ng-animate="fade"></div>')(scope);
                elm.append(v);
                return v;
            };

            scope.setView = function (view) {
            };

            scope.removeView = function () {
            };
        }
    };
}]);

styles.css

.fade-enter-setup { -webkit-transition: all 3s linear; opacity: 0; }
.fade-enter-setup { opacity: 1; }

partial1.html

<div>Hello I am a partial 1</div>

partial2.html

<div>PARTIAL 2-------------------</div>

partial3.html

<div>
33333333333333333333333333
<br />
this is partial 3
<br />
33333333333333333333333333
</div>
Share Improve this question asked May 9, 2013 at 12:49 romiemromiem 9,0407 gold badges32 silver badges37 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

If you are still interested, i accidently created a plunker today, that should answer your long ago question.

http://plnkr.co/Gd5f6J

Now with the latest 1.2 stable release, if angular finds ngAnimate module, it will add specific css classes to the dom, when a built-in directive like ng-if, ng-switch, ng-view detected, that a child has changed. Those classes trigger your css transitions, so if your view partial takes a long time to load, the animation will start, when it was fully loaded.

index.html:

<div class="view-animate-container">
  <div class="well slide" ng-view>
    <!-- view container. Asynchronously loaded view templates are placed here -->
  </div>
</div>

app.js:

angular.module('myApp', ['ngRoute', 'ngAnimate'])
.run(function($rootScope, $location){
  $rootScope.matchesRoute = function() {
    for(var i=0; i<arguments.length; i++) {
      if($location.path() === arguments[i]) {
        return true;
      }
    }
    return false;
  }
})
.config(function($routeProvider) {
    $routeProvider
      .when('/bellsAndWhistles', {templateUrl: 'bellsAndWhistles.html', controller: angular.noop()})
      .when('/about',            {templateUrl: 'about.html',            controller: angular.noop()})
      .otherwise({redirectTo: '', templateUrl: 'home.html'});
});

styles.css:

html, body{
  height: 100%;
}

.view-animate-container {
    position: relative;
    overflow: hidden;
    height:100%;
}

.view-animate-container > .slide.ng-enter,
.view-animate-container > .slide.ng-leave {
    -webkit-transition: all ease 0.5s;
       -moz-transition: all ease 0.5s;
         -o-transition: all ease 0.5s;
            transition: all ease 0.5s;  
    width: 100%;
    position:absolute;
}

.view-animate-container > .slide.ng-enter {
    left:100%;
    opacity: 0;
}
.view-animate-container > .slide.ng-enter.ng-enter-active {
    left:0;
    opacity: 1;
}
.view-animate-container > .slide.ng-leave.ng-leave-active {
    left: -100%;
    opacity: 0;
}

I came across this same issue. However, the behavior of content below the animated view will be jumpy and undesired. See this Plunker Example.

So, to expand on @angabriel 's answer, I worked on an alternative. See the following Plunker Example, which is a modification of @angabriel's work. You will need to use Chrome to see it working, since I did not had the chance to add the css for other browsers.

The main difference is the CSS. It is worth mentioning that I had to override the following:

  • min-height
  • margin-top
  • margin-bottom
  • padding-top
  • padding-bottom

To make the transition smooth, since bootstrap adds some rules that make the transition jumpy once the element that leaving is removed from the DOM.

/* CSS */
.view-animate-container > .slide.ng-enter,
.view-animate-container > .slide.ng-leave {
    -webkit-transition: all ease 0.5s;
    -moz-transition: all ease 0.5s;
    -o-transition: all ease 0.5s;
    transition: all ease 0.5s;
    width: 100%;
    position: relative;
}

.view-animate-container > .slide.ng-enter {
    -webkit-animation-name: slideIn;
    animation-name: slideIn;
    -webkit-animation-duration: .5s;
    animation-duration: .5s;
    -webkit-animation: slideIn .5s;
    animation: slideIn .5s;
}

.view-animate-container > .slide.ng-leave {
    -webkit-animation-name: slideOut;
    animation-name: slideOut;
    -webkit-animation-duration: .5s;
    animation-duration: .5s;
    -webkit-animation: slideOut .5s;
    animation: slideOut .5s;
}

@keyframes slideOut {
    from {
        opacity: 1;
        max-height: 500px;
    }
    50% {
        opacity: 0;
        max-height: 0px;
        margin-top: 0;
        min-height: 0;
        margin-bottom: 0;
        padding-bottom: 0;
        padding-top: 0;
    }
    to {
        opacity: 0;
        max-height: 0px;
        margin-top: 0;
        min-height: 0;
        margin-bottom: 0;
        padding-bottom: 0;
        padding-top: 0;
    }
}

@keyframes slideIn {
    from {
        opacity: 0;
        max-height: 0px;
        margin-top: 0;
        min-height: 0;
        margin-bottom: 0;
        padding-bottom: 0;
        padding-top: 0;
    }
    50% {
        max-height: 0;
        opacity: 0;
        margin-top: 0;
        min-height: 0;
        margin-bottom: 0;
        padding-bottom: 0;
        padding-top: 0;
    }
    to {
        max-height: 500px;
        opacity: 1;
    }
}

PROS

Content below the view div will not be jumpy

CONS

Content height: If the view content is grater than 500px (in my case) it will animate to 500px then jump to its full height (as pointed out by Isaac)

Thanks

本文标签: javascriptAngularJShow to animate nginclude that is dynamically compiled and addedStack Overflow