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
,