Angular.js: ng-show / hide wird für ein animiertes Element verzögert

Erstellt am 16. Juli 2014  ·  17Kommentare  ·  Quelle: angular/angular.js

Dies ist kein zu erwartendes Verhalten, wenn Sie eine konstante Animation für etwas wie einen Ladespinner ausführen und es nur sofort ausblenden oder anzeigen möchten.

Dem Element wurde nicht gesagt, dass es von ng-animate verwaltet werden soll. Ich möchte nur, dass normales ng-show / hide sofort ausgeführt wird, und alle laufenden CSS-Animationen sollten irrelevant sein, denke ich.

Geige: http://jsfiddle.net/PvS8k/2/

Deaktivieren Sie "show loader" und beachten Sie, dass es einige Sekunden dauert, bis der Vorgang tatsächlich beendet ist.

Ich denke, dies ist eine kürzlich vorgenommene Änderung, da unser Loader vor dem Upgrade nicht in unserer Anwendung steckte. Ich denke, wir waren vorher am 1.12.

Ich muss etwas in meinem Verständnis darüber vermissen, wie man ng-animate benutzt / nicht benutzt, oder? In diesem Fall möchte ich es eigentlich NICHT verwenden, aber wenn ich es verwenden kann, um dieses Element zu ignorieren, würde das auch funktionieren. Auf jeden Fall überraschendes Verhalten.

ngAnimate broken expected use bug

Hilfreichster Kommentar

@ tole42 Dies ist die

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

Alle 17 Kommentare

ngAnimate ist gierig, da davon ausgegangen wird, dass alle Keyframes / Übergangscodes, die während eines der Trigger auf dem Element aktiv sind, über ngAnimate animiert werden sollen. Daher wird es in diesem Fall, obwohl .loader nichts mit ngShow / ngHide zu tun hat, immer noch als gültige Animation aufgenommen.

Um dies zu umgehen, löschen Sie einfach das Animations-Styling, wenn die Klasse .ng-animate auf das Element angewendet wird.

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

Dies ist ein Problem mit der CSS-Vererbung. Wenn es eine bessere Möglichkeit gäbe, Stile zu erkennen, ohne sich ausschließlich auf getComputedStyle verlassen zu müssen, könnten solche Macken möglicherweise vermieden werden.

@matsko Ich denke, dieser Sonderfall ist eigentlich eine Regression. Wie Sie im Plunker von @SimpleAsCouldBe oder in diesem Plunker http://plnkr.co/edit/5cfIXfNryNOzK66q9YWL?p=preview sehen können , verschwindet das Element in 1.2.17 nicht sofort, sondern in 1.2.16 tut. Dies liegt höchstwahrscheinlich an https://github.com/angular/angular.js/commit/55b2f0e8620465559016b424967d90a86af597c0
Ich denke, dies rechtfertigt eine etwas genauere Betrachtung. Zumindest sollte das Änderungsprotokoll und die Dokumentation dazu einen Hinweis enthalten.

Vielen Dank für die Problemumgehung, es macht den Trick wie erwartet.

Zwei Punkte. Einer ist spezifisch für ng-show und einer ist allgemein.

ng-show + unendliche animationen:

Sollte eine unendliche Animation das Verstecken eines ng-show wirklich verzögern? Ich habe versucht, Sekunden zu zählen, und es dauert nicht immer 4 Sekunden, bis es ausgeblendet ist. Manchmal scheinen seine 5 oder 7 ... zu variieren. Auch wenn Sie das Kontrollkästchen ein- und ausschalten, wird es nie ausgeblendet. Ich denke, hier versteckt sich irgendwo ein Fehler.

Philisophisch

Als Nicht-Mitwirkender habe ich nicht viel zu sagen, aber vielleicht ist Opt-out nicht die richtige Strategie für diese Bibliothek. Es ist einfach so erstaunlich magisch, wenn eine JS-Bibliothek auf CSS-Regeln reagiert. Wenn ich Elemente mit ng-animatable markieren müsste, wäre ich viel besser darauf vorbereitet.

@SimpleAsCouldBe Ja, ich habe das gleiche gedacht, dass es vielleicht am besten ist, alle Animationen mit einem Klassenpräfix von animate- , damit ngAnimate sich dann in die Animationen einhakt.

In Bezug auf die Verzögerung ist es nicht so, dass es eine Verzögerung gibt, sondern dass ngAnimate den unendlichen Teil abbricht und die Animation nur einmal ausführt. Wenn Sie es ausblenden, wartet es daher 2 Sekunden * 1,5 = 3 Sekunden und führt dann die Zeitüberschreitungsprüfung aus und schließt die Animation. Es ist also ein unnötiges Zeitfenster, das überhaupt nicht vorhanden sein sollte - nur die Erkennung von CSS-Stilen ist stark eingeschränkt.

@Narretz Während das von Ihnen bereitgestellte Commit dieses Beispiel beeinflussen kann, hat es eigentlich nichts mit der Regression zu tun. Der Grund dafür ist, dass das .ng-hide -Stiling, das vor dem Fix vorhanden war, den display:none -Wert zu einem anderen Zeitpunkt angewendet hat. Das aktuelle Update wendet es jedoch NUR an, nachdem alle Animationen abgeschlossen sind (sobald die Klasse .ng-animate entfernt wurde).

Schauen Sie sich die Demo unten an. Sehen Sie, wie es zwei Sätze von Selektoren für die Klasse .blue : einen mit .ng-animate und ohne. Obwohl die .blue -Klasse sofort angewendet wird, glaubt ngAnimate immer noch, dass eine Animation fällig ist, und wartet auf 3s (denken Sie an 2s * 1.5), bevor Sie ein Zeitlimit für das Schließen anwenden. Normalerweise wäre es 2s, aber ein animationend -Ereignis wird nie ausgelöst, da die eigentliche Animation des Elements (die aufgrund von .loader ) unendlich ist und nicht von der ng-Klasse ausgelöst wird ( oder ng-show für das vorherige Beispiel). Dies wird jedoch aufgrund der vorherigen Fehlerbehebung nicht bewirkt.
http://jsfiddle.net/PvS8k/15/

Es ist möglicherweise am besten, ngAnimate weniger naiv zu machen und nur dann zu animieren, wenn animated- irgendwo als CSS-Präfix vorhanden ist.

Ich denke, wenn Sie offen für eine bahnbrechende Änderung wie die Bearbeitung von Opt-In-Animationen sind, würde dies zu einer weniger überraschenden Entwicklererfahrung führen.

Wären Sie offen für Präfixe mit etwas Winkelspezifischem wie .ng-animate anstelle von einfach altem .animate ?

Ich habe das gleiche Problem:
Mit Winkel> = 1.2.17 http://jsfiddle.net/9krLr/17/
Mit eckigem 1.2.16 ist alles in Ordnung: http://jsfiddle.net/EZpQQ/1/

@ tole42 Dies ist die

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

Danke für Ihre Hilfe. Die Problemumgehung funktioniert nicht :(
Was ist falsch?
http://jsfiddle.net/9krLr/21/

@ tole42 Soweit ich sehen kann, animiert nichts in dieser Geige. Ist die Animation Teil der Foundation-Bibliothek? Ein direkterer Fall der Neuerstellung würde das Debuggen erleichtern. Sieht für mich nicht nach dem gleichen Problem aus.

Ich glaube, ich sehe das gleiche Problem wie @ tole42 . Mit ngAnimate include in einem Modul funktioniert die Standardfunktion ng-hide / ng-show für den Basisfall nicht richtig, wenn Sie nicht versuchen, sie zu animieren. Mit anderen Worten, wenn Sie ng-hide / ng-show für ein einfaches Element ohne angewendete Animationsklasse verwenden.

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

Wenn ich eine Animation auf diesem Fell haben wollte, würde ich etwas tun wie:

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

Es gibt einige Fälle in einer App, in denen Sie ein Ein- / Ausblenden animieren möchten, und andere Fälle, in denen Sie nicht animieren möchten. In den Fällen, in denen Sie nicht animieren möchten, dekorieren Sie das angezeigte / ausgeblendete Element nicht mit einer benutzerdefinierten Animationsklasse. In diesem Fall fügt Angular einem versteckten Element nur die Klasse "ng-hide" hinzu.

Wenn Sie ngAnimate überhaupt nicht in Ihr Modul aufnehmen, funktioniert dies wie erwartet: Das Element verschwindet sofort. Durch einfaches Einschließen von ngAnimate erhalten Sie jedoch das Verhalten, das in den beiden von @ tole42 geposteten Fiddles

Einige Workarounds, die zu funktionieren scheinen, sind:

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

Oder:

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

Es scheint jedoch nicht richtig zu sein, dass diese erforderlich sein sollten, wenn Sie lediglich versuchen, etwas nicht animiert zu verbergen.

Nur um einige zusätzliche Entdeckungen zu verfolgen ...

Beim Versuch, das Problem auf ein möglichst einfaches Szenario zu reduzieren - das Ein- und Ausblenden von einfachen Divs - tritt das Problem nicht auf.

Ich habe in den von @ tole42 geposteten Fiddles Datei foundation.css verwendet wurde, und das Beispiel zeigt das Problem beim Ein- / Ausblenden von Eingabefeldern. Meine Erfahrung war ähnlich (das Problem manifestiert sich mit Eingabefeldern), aber mit bootstrap.css. Bei genauerer Betrachtung dieser beiden CSS-Dateien wenden beide CSS-Übergänge auf Eingabefelder an.

Diese CSS-Übergänge scheinen der eigentliche Schuldige zu sein, da Angular-Animate die Dauer von ihnen aufnimmt. Dies verursacht die visuelle Verzögerung beim Ein- / Ausblenden dieser Elemente, auch wenn Sie nicht absichtlich versuchen, diesen Übergang zu animieren.

Ich denke also nicht, dass dies notwendigerweise ein Problem ist, das Angular zu lösen versuchen sollte. Es ist eher ein Nebeneffekt der Verwendung von Angular-Animate mit anderen CSS-Bibliotheken, die möglicherweise einige eingebettete CSS-Übergänge aufweisen, die Sie nicht erwarten!

Es hat lange gedauert, die Grundursache aufzuspüren, aber es war gut, endlich einen Grund zu finden, der Sinn macht.

Ja, dies ist ein wichtiges Problem bei ngAnimate, aber aufgrund der mangelnden Kontrolle über getComputedStyle und der Kaskade von Übergängen in anderen Bibliotheken kann ngAnimate dies nicht erkennen.

Es gibt zwei Lösungen, um dies zu beheben:

1) Überschreiben Sie das Styling für die Klasse .ng-animate :
http://jsfiddle.net/9krLr/27/

Der Grund, warum es bei Ihnen vorher nicht funktioniert hat, war die mangelnde CSS-Spezifität.

2) Verwenden Sie $animateProvider.classNameFilter(regex) . Der reguläre Ausdruck in diesem Fall setzt einen harten Block für alle von ngAnimate ausgelösten Animationen und lässt die Animation nur zu, wenn der reguläre Ausdruck mit einem Klassennamen übereinstimmt, der auf dem Element vorhanden ist, das animiert werden soll.

Oh, die Konfiguration in einen Provider zu stecken ist ein guter Weg, das gefällt mir sehr gut, @matsko!

@pnutshellmenace danke für die schnelle Lösung. Es hat mir den Tag gerettet.

Ich verstehe nicht, was die endgültige Lösung hier war. @matsko erklärte:

Es ist möglicherweise am besten, ngAnimate weniger naiv zu machen und nur dann zu animieren, wenn es animiert ist - gibt es irgendwo ein CSS-Präfix

Aber ich sehe keine solche Implementierung. Ich habe mir $animateProvider.classNameFilter(regex) aber ich habe wieder mehr Fragen als Antworten. Was ist ein praktischer Weg, um dies zu implementieren, und was ist, wenn mehr als ein Klassenname anwendbar ist?

Ich sehe keinen Grund, warum ngAnimate davon ausgehen sollte, dass ich alles animieren möchte. Es wird immer Dinge geben, die ich nicht animieren möchte, und derzeit habe ich mehr, die ich nicht animieren möchte, als umgekehrt, was das manuelle Stylen dieser Übergänge zum Deaktivieren von Übergängen unattraktiv macht.

Bearbeiten: Ich habe diesen Blogeintrag gefunden, der die Dinge relativiert ... Ich werde es versuchen: http://blog.fgribreau.com/2014/03/how-to-configure-ng-animate-to- work-on.html

Bearbeiten 2: Das Hinzufügen von $animateProvider.classNameFilter(/enable-animate/); funktioniert, aber dabei habe ich ein interessantes Verhalten festgestellt:

Ich hatte eine .js-Datei eines Winkelmoduls eines Drittanbieters eingefügt, das von ngAnimate abhängig war, und irgendwie wurden Animationen sogar auf meinem eigenen Modul ausgelöst. Irgendwie hat ngAnimate den Umfang des übergeordneten Moduls beeinflusst?

Ich würde diese Antwort mit $scope.$evalAsync(); für asynchrone Operationen vorziehen. funktioniert gut.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen