问题
This is a heavily simplified demo of ng-class
animation using transition that I'm trying to achieve.
I'm trying to create a simple fade in animation when an item is selected.
Selecting an item will add a selected
class on it using ng-class
directive. I'm trying to add a transition to it following the documentation with the animation hook classes added by ng-animate
.
Below is the code I have so far. It sets the opacity
to 0
along with the transition property, and when the .selected-add-active
class is added it is supposed to transition to opacity
1. But it does not work.
angular.module('demo', ['ngAnimate'])
.controller('demoCtrl', function($scope) {
$scope.selected = false;
$scope.selectToggle = function() {
$scope.selected = !$scope.selected;
};
});
.item {
width: 50px;
height: 50px;
background: grey;
}
.item.selected {
background-color: dodgerblue;
}
.item.selected.selected-add {
transition: opacity 3s;
opacity: 0;
}
.item.selected.selected-add.selected-add-active {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-animate.js"></script>
<div ng-app="demo" ng-controller="demoCtrl">
<div class="item" ng-class="{selected:selected}"></div>
<br>
<br>
<button ng-click="selectToggle();">
{{selected? 'Unselect' : 'Select'}}
</button>
</div>
Why isn't my code working?
回答1:
The problem here seems to be the order in which angular ng-animate applies the CSS classes and how browser optimizes DOM reflows.
ng-animate
initially adds the x-add
class prior to actually adding class x
. This is where it forces(or fakes) a DOM reflow so that browser detects the initial state for animation.
But since the selector for initial state's CSS (.item.selected.selected-add
) is chained with .selected
class which isn't added yet, it doesn't match anything and browser ignores it.
After this, ng-animate
adds the selected
class followed by selected-add-active
class. At this point the CSS selector for initial state does match, but these changes happens in the same reflow, hence the browser chooses to apply opacity
from the selector with highest specificity which is
.item.selected.selected-add.selected-add-active {
opacity: 1;
}
Now since no actual change in the element's opacity
is detected, no transition takes place.
To fix this, avoid chaining the animation hook classes added by ng-animate
with the class being toggled. Especially the x-add
class which should be detected by the browser before the following classes gets applied.
Below is a working example:
angular.module('demo', ['ngAnimate'])
.controller('demoCtrl', function($scope) {
$scope.selected = false;
$scope.selectToggle = function() {
$scope.selected = !$scope.selected;
};
});
.item {
width: 50px;
height: 50px;
background: grey;
}
.item.selected {
background-color: dodgerblue;
}
.item.selected-add {
transition: opacity 3s;
opacity: 0;
}
.item.selected-add.selected-add-active {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-animate.js"></script>
<div ng-app="demo" ng-controller="demoCtrl">
<div class="item" ng-class="{selected:selected}"></div>
<br>
<br>
<button ng-click="selectToggle();">
{{selected? 'Unselect' : 'Select'}}
</button>
</div>
来源:https://stackoverflow.com/questions/38124889/why-is-ng-class-based-ng-animate-transition-not-working