Почему не работает переход ng-animate на основе класса ng?

Это сильно упрощенная демонстрация анимации ng-class с использованием перехода, которую я пытаюсь реализовать.

Я пытаюсь создать простую анимацию затухания при выборе элемента.

Выбор элемента добавит к нему класс selected с помощью директивы ng-class. Я пытаюсь добавить к нему переход, следуя документации с классами хуков анимации, добавленными ng-animate.

Ниже приведен код, который у меня есть до сих пор. Он устанавливает opacity в 0 вместе со свойством перехода, и когда добавляется класс .selected-add-active, предполагается переход в opacity 1. Но это не работает.

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>

Почему мой код не работает?


person T J    schedule 30.06.2016    source источник


Ответы (1)


Проблема здесь, по-видимому, заключается в порядке, в котором angular ng-animate применяет классы CSS, и в том, как браузер оптимизирует перекомпоновки DOM.

ng-animate сначала добавляет класс x-add до фактического добавления класса x. Именно здесь он принудительно (или имитирует) перекомпоновку DOM, чтобы браузер определял начальное состояние для анимации.

Но поскольку селектор для CSS начального состояния (.item.selected.selected-add) связан с классом .selected, который еще не добавлен, он ничему не соответствует, и браузер его игнорирует.

После этого ng-animate добавляет класс selected, за которым следует класс selected-add-active. В этот момент селектор CSS для начального состояния действительно совпадает, но эти изменения происходят в том же перекомпоновке, поэтому браузер выбирает применение opacity из селектора с наивысшей специфичностью, который

.item.selected.selected-add.selected-add-active {
  opacity: 1;
}

Теперь, поскольку фактическое изменение opacity элемента не обнаружено, переход не происходит.


Чтобы исправить это, избегайте связывания классов обработчиков анимации, добавленных ng-animate, с переключаемым классом. Особенно класс x-add, который должен быть обнаружен браузером до того, как будут применены следующие классы.

Ниже приведен рабочий пример:

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>

person T J    schedule 30.06.2016