Angular.js: ng-show / hide задерживается на элементе, который анимирует

Созданный на 16 июл. 2014  ·  17Комментарии  ·  Источник: angular/angular.js

Это не ожидаемое поведение, если вы делаете постоянную анимацию для чего-то вроде загрузочного счетчика и просто хотите немедленно скрыть или показать это.

Элементу не было сказано, что он управляется ng-animate, я просто хочу, чтобы нормальное ng-show / hide происходило мгновенно, и любые анимации css, которые происходят, я думаю, не должны иметь значения.

Скрипка: http://jsfiddle.net/PvS8k/2/

Снимите флажок «Показать загрузчик» и обратите внимание, что на самом деле требуется несколько секунд, чтобы исчезнуть.

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

Мне должно быть что-то не хватает в моем понимании того, как использовать / не использовать ng-animate, верно? В этом случае я действительно хочу НЕ использовать его, но если я могу использовать его для игнорирования этого элемента, это тоже сработает. Определенно удивительное поведение.

ngAnimate broken expected use bug

Самый полезный комментарий

@ Толе42 Это обходной путь:

.YourElementClass.ng-animate { -webkit-animation: none 0s; }

Все 17 Комментарий

ngAnimate жаден, поскольку предполагает, что все ключевые кадры / код перехода, которые активны в элементе во время любого из триггеров, должны быть анимированы с помощью ngAnimate. Следовательно, в этом случае, несмотря на то, что .loader имеет ничего общего с ngShow / ngHide, он по-прежнему воспринимается как допустимая анимация.

Чтобы обойти это, просто удалите стиль анимации, когда к элементу применяется класс .ng-animate .

http://jsfiddle.net/PvS8k/4/

Это проблема наследования CSS. Если бы существовал лучший способ обнаружения стилей, не полагаясь исключительно на getComputedStyle, можно было бы избежать подобных причуд.

@matsko Я думаю, что этот частный случай на самом деле регресс. Как вы можете видеть в плункере @SimpleAsCouldBe или в этом плунжере http://plnkr.co/edit/5cfIXfNryNOzK66q9YWL?p=preview , в 1.2.17 элемент не исчезает сразу, но в 1.2.16 он делает. Скорее всего, это из-за https://github.com/angular/angular.js/commit/55b2f0e8620465559016b424967d90a86af597c0
Я думаю, это требует более внимательного изучения; по крайней мере, в журнале изменений и документации должна быть заметка об этом.

Спасибо за обходной путь, он работает, как и ожидалось.

Два очка. Один является специфическим для ng-show, а другой - общим.

ng-show + бесконечные анимации:

Должна ли бесконечная анимация действительно_ задерживать шкуру ng-show ? Я пробовал считать секунды, и не всегда он ждет 4 секунды, чтобы скрыть это. Иногда его 5 или 7 ... кажется, разные. Также, если вы снова включите и выключите флажок, он никогда не скроется. Я думаю, что где-то здесь прячется настоящая ошибка.

Философский

Как не участник, я мало что могу сказать, но, возможно, отказ от участия - неправильная стратегия для этой библиотеки. Это так поразительно волшебно, когда библиотека JS реагирует на правила CSS ... Если бы мне пришлось помечать элементы с помощью ng-animatable я был бы гораздо более подготовлен к этому.

@SimpleAsCouldBe, да, я тоже думал о том, что, возможно, лучше всего потребовать, чтобы все анимации имели префикс класса animate- , чтобы ngAnimate затем подключался к анимации.

Что касается задержки, дело не в задержке, а в том, что ngAnimate отменяет бесконечную часть и запускает анимацию только один раз. Поэтому, когда вы его скрываете, он ждет 2 с * 1,5 = 3 секунды, а затем запускает проверку тайм-аута и закрывает анимацию. Так что это ненужное временное окно, которого вообще не должно быть - только определение стилей CSS сильно ограничено.

@Narretz, хотя предоставленная вами фиксация может повлиять на этот конкретный пример, на самом деле она не имеет ничего общего с регрессией. Причина этого в том, что стиль .ng-hide который был до исправления, применял значение display:none в другое время. Но текущее исправление применяется ТОЛЬКО после завершения всех анимаций (после удаления класса .ng-animate ).

Посмотрите демо ниже. Посмотрите, как есть два набора селекторов для класса .blue : один с .ng-animate и без него. Несмотря на то, что класс .blue применяется немедленно, ngAnimate по-прежнему считает, что должна быть анимация, и будет ждать 3s (помните, 2s * 1.5) перед применением тайм-аута закрытия. Обычно это 2 секунды, но событие animationend никогда не запускается, поскольку фактическая анимация элемента (которая существует из-за .loader ) бесконечна и не запускается ng-class ( или ng-show для предыдущего примера). Так что, как говорится, это не происходит из-за предыдущего исправления ошибки.
http://jsfiddle.net/PvS8k/15/

Возможно, лучше сделать ngAnimate менее наивным и анимировать только тогда, когда animated- присутствует где-то в качестве префикса CSS.

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

Будете ли вы открыты для префикса с чем-то специфическим для angular, например .ng-animate а не с обычным .animate ?

У меня та же проблема:
С угловым> = 1.2.17 http://jsfiddle.net/9krLr/17/
С angular 1.2.16 все в порядке: http://jsfiddle.net/EZpQQ/1/

@ Толе42 Это обходной путь:

.YourElementClass.ng-animate { -webkit-animation: none 0s; }

Спасибо за вашу помощь. Обходной путь не работает :(
Что не так?
http://jsfiddle.net/9krLr/21/

@ Tole42 Насколько я могу

Я считаю, что вижу ту же проблему, что и @ толе42 . При включении ngAnimate в модуль стандартные функции ng-hide / ng-show не работают правильно для базового случая, когда вы _не_ пытаетесь их анимировать. Другими словами, когда вы используете ng-hide / ng-show для простого элемента без применения класса анимации.

<div ng-hide="hideme">hide me</div>

Если бы мне нужна была анимация на этой шкуре, я бы сделал что-то вроде:

<div ng-hide="hideme" class="myanimation">hide me</div>

В приложении есть некоторые экземпляры, в которых вы можете захотеть анимировать отображение / скрытие, и другие экземпляры, в которых вы не хотите анимировать. В тех случаях, когда вы не хотите анимировать, вы не украшаете отображаемый / скрытый элемент каким-либо настраиваемым классом анимации. В этом случае Angular просто добавляет класс «ng-hide» к скрытому элементу.

Если вы вообще не включаете ngAnimate в свой модуль, это работает должным образом: элемент немедленно исчезает. Но, просто включив ngAnimate, вы получите поведение, показанное в двух скриптах, опубликованных

Вот пара обходных путей, которые кажутся работоспособными:

.ng-hide-add {
    transition: 0s linear all;
}

Или же:

.ng-hide {
    display: none !important;
}

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

Просто чтобы следить за некоторыми дополнительными открытиями ...

Попытка свести проблему к простейшему возможному сценарию - показать / скрыть простые div - проблема не проявляется.

Я заметил, что в скриптах, опубликованных @ Толе42 , использовался

Эти переходы css кажутся настоящими виновниками, поскольку angular-animate берет от них длительность. Это то, что вызывает визуальную задержку при отображении / скрытии этих элементов, даже если вы намеренно не пытаетесь анимировать этот переход.

Так что я не думаю, что это обязательно проблема, которую Angular должен пытаться решить. Это скорее побочный эффект использования angular-animate с другими библиотеками css, которые могут иметь некоторые встроенные переходы css, которых вы не ожидаете!

Потребовалось много времени, чтобы найти первопричину, но было хорошо, наконец, найти причину, которая имеет смысл.

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

Есть два способа исправить это:

1) Переопределите стиль для класса .ng-animate :
http://jsfiddle.net/9krLr/27/

Причина, по которой это не сработало раньше, заключалась в отсутствии специфичности CSS.

2) Используйте $animateProvider.classNameFilter(regex) . Регулярное выражение в этом случае поместит жесткий блок на все анимации, запускаемые ngAnimate, и разрешит анимацию только в том случае, если регулярное выражение соответствует className, которое присутствует в элементе, который вы хотите анимировать.

О, размещение конфигурации в провайдере - отличный способ, мне это очень нравится, @matsko!

@pnutshellmenace благодарит за быстрое решение. Это спасло мне день.

Я не понимаю, какое здесь было окончательное решение. @matsko заявил:

Возможно, лучше сделать ngAnimate менее наивным и анимировать только при анимации - есть ли где-то префикс CSS

Но я не вижу такой реализации. Я взглянул на $animateProvider.classNameFilter(regex) но опять же, у меня осталось больше вопросов, чем ответов. Каков практический способ реализовать это и что, если применимо более одного имени класса?

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

Изменить: нашел эту запись в блоге, которая рассматривает ситуацию в перспективе ... Я собираюсь попробовать: http://blog.fgribreau.com/2014/03/how-to-configure-ng-animate-to- work-on.html

Изменить 2: добавление $animateProvider.classNameFilter(/enable-animate/); сработало, но в процессе я обнаружил интересное поведение:

Я включил файл .js стороннего модуля angular, который зависел от ngAnimate, и каким-то образом это вызывало запуск анимации даже в моем собственном модуле. Каким-то образом ngAnimate влиял на область видимости родительского модуля?

Я бы предпочел, чтобы этот ответ использовал $scope.$evalAsync(); для асинхронной операции. работает хорошо.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги