ng-animate: добавляется в домен только после задержки анимации

Я пытаюсь использовать ng-animate с ng-repeat (а также ng-show) исчезнуть старый контент и заменить его новым.

У меня проблема в том, что во время remove а также add анимации, как добавляемый элемент (ы), так и удаляемый элемент (ы) имеют display:block,

Я думал, что могу избежать этого, используя animation-delay в CSS, но это только задерживает исчезновение, а не добавление класса, который устанавливает display на элементе.

Результатом является резкий переход.

Это моя анимация CSS (вырублена):

.keyframe-fade.ng-enter,
.keyframe-fade.ng-move {
  animation: 0.5s fade-in;
  animation-delay: 1s;
  animation-fill-mode: backwards;
}
.keyframe-fade.ng-leave {
  animation: 0.5s fade-out;
}

Но это легче продемонстрировать с этим планкром.

Есть идеи?

ПРИМЕЧАНИЕ: для ясности, желаемое поведение связанного с plunkr состоит в том, что цветные квадраты всегда занимают одно и то же место, то есть они находятся на одной линии, а кнопка не двигается. Если возможно, я бы хотел исправить это без абсолютного позиционирования 'bodges', так как фактическая страница, на которой я это использую, намного сложнее, чем приведенная демонстрация.

2 ответа

Решение

Решение, которое я нашел для этого, состоит в том, чтобы дополнить чистую анимацию CSS небольшим количеством JavaScript.

Чтобы подвести итог проблемы:

  • Элемент ввода добавляется в DOM с ng-enter класс в то же время, что оставляющий элемент дается ng-leave учебный класс.

  • Несмотря на задержку анимации, входящий элемент по-прежнему занимает место

Так что этот кусок JavaScript берет элемент и добавляет ng-hide на время анимации ухода, удаляя ее потом.

.animation('.keyframe-fade', ['$timeout', function ($timeout){
  return {
    enter: function (element, done){

      // Add ng-hide for the duration of the leave animation.
      element.addClass('ng-hide');

      $timeout(function(){
        element.removeClass('ng-hide');
      }, 500)

      done();

    }
  }
}])

Длительность здесь жестко запрограммирована, но я не вижу причин, по которым вы не могли бы взять ее вместо элемента.

Улучшения / предложения приветствуются.

Вот оригинальный планкр с изменением.

Это ужасно, и для Angular 2+, но только для записи вот одна идея.

У меня два button элементы, один, когда у пользователя есть товары в корзине, и один, когда его нет.

Самый простой способ - это поставить position: relative на родительском DIV и position: absolute на обеих кнопках. Основным недостатком является то, что родительский DIV должен измеряться вручную, а такие вещи, как центрирование, становятся более сложными.


Если цель состоит в том, чтобы отложить добавление в DOM на основе наблюдаемого значения, то я подумал: " Почему бы просто не отложить наблюдаемое значение? ', который будет иметь тот же конечный эффект. Это нужно делать только тогда, когда переход от false> true, хотя вы хотите скрыть его только тогда, когда он появляется. Поэтому я использовал трубу, чтобы справиться с этим.

    <!-- This button for when item is IN the cart -->
    <button [@cartIconAnimation] *ngIf="showCartIcon | delayTrue | async">View Cart</button>

    <!-- This button for when item is NOT IN the cart -->
    <button [@cartIconAnimation] *ngIf="showCartIcon | complement | delayTrue | async">Add to Cart</button>

Это предполагает showCartIcon является Observable<boolean>,

Тогда каналы следующие, и по вашим критериям анимации не требуется никаких задержек.

@Pipe({
    name: 'delayTrue'
})
export class DelayTruePipe implements PipeTransform {

    constructor() {}

    transform(value: Observable<any> | any, delay: number): Observable<any> {
        if (isObservable(value)) {
            return value.pipe(distinctUntilChanged(), debounce((show) => show ? timer(delay || 500) : empty()));
        } else {
            throw Error('Needs to be an observable');
        }
    }
}

@Pipe({
    name: 'complement'
})
export class ComplementPipe implements PipeTransform {

    constructor() {}

    transform(value: Observable<boolean> | any): Observable<any> {
        if (isObservable(value)) {
            return value.pipe(map(i => !i));
        } else {
            throw Error('Needs to be an observable');
        }
    }
}

Примечание. Задержка, используемая каналом, должна превышать время, необходимое для исчезновения предыдущего элемента, иначе возникнет та же проблема.

Канал комплемента просто инвертирует логическое значение.

Это решение работает, но оно хакерское, и время может быть труднее ошибиться, и могут возникнуть условия гонки, когда два разных таймера браузера запускаются одновременно. Я бы сделал что-то подобное, если ты действительно не можешь использовать position: absolute,

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