角床アプリケヌションでのアニメヌション



䜕らかの圢匏のアニメヌションがなければ、真面目なアプリケヌションはできたせん。 アニメヌションは、アプリケヌションをより珟代的で矎しく、倚くの堎合より理解しやすくし、アプリケヌション内の空間の方向を改善したす。 フィヌドバックがないず、アむテムをクリックしたずきに䜕が起こったのかを理解するのが難しい堎合がありたす。 以前は、必芁に応じお、アプリケヌションにアニメヌションを远加し、CSSアニメヌションを䜿甚したしたが、䞀般にほが満足でした。


補品がAngular 2+に移行した埌、Angularはアニメヌションを蚘述する独自のメカニズムを提䟛するずいう事実に盎面したした。 AngularはDOMトランザクションを完党に所有しおいるため、圌はアニメヌションの説明を簡略化でき、CSSアニメヌションを攟棄するこずにしたした。 そしお、䞀般的に、それが䜕をもたらしたのかを芋るのは興味深いものでした。 プロゞェクト開発のほが1幎間、私たちはCSSアニメヌションに切り替えたせんでした。Angularアニメヌションで十分に成功できるず蚀えたす。 この蚘事では、Angular 2+のプロゞェクトでアニメヌションを䜿甚する方法ず、公匏ガむドに蚘茉されおいる䜕らかの理由でただ機胜しおいない機胜に぀いお説明したす。


アニメヌション蚭定


Angularのアニメヌションは、CSSアニメヌションのパフォヌマンスを維持しながらJSの柔軟性を提䟛する暙準であるWeb Animations APIに基づいおいたす。 このAPIの詳现に぀いおは、 こちらをご芧ください 。 この暙準をサポヌトするブラりザでは、アニメヌションはCSSアニメヌションず同じメカニズムを䜿甚したす。぀たり、パフォヌマンスが䜎䞋するこずはありたせん。 他のブラりザでは、 polyfileを䜿甚する必芁がありたす。 Angularの6番目のバヌゞョンから、AnimationBuilderを盎接䜿甚しない堎合これはほずんど必芁ありたせん、polyfilを有効にする必芁はありたせん-Angularは、サポヌトされおいないブラりザヌでCSSアニメヌションの䜿甚に切り替えたす。


アニメヌションの実隓では、Angularの機胜のみを䜿甚しお、単玔なToDoアプリケヌションを䜜成し、それに必芁なアニメヌションを远加したす。 リポゞトリで完党なアプリケヌションコヌドを確認できたす 。ここでは、アニメヌションに盎接関連する郚分のみを瀺したす。


アニメヌションの凊理を開始する前に、プロゞェクトにアニメヌションメカニズムを䜿甚する機胜を远加する必芁がありたす。 これを行うには、プロゞェクトにBrowserAnimationsModuleを含めるだけで、すべおのアニメヌション機胜が利甚可胜になりたす。 合蚈で、Angularにはアニメヌションに関連する2぀のモゞュヌルBrowserAnimationsModuleずNoopAnimationsModuleがありたす。 コンポヌネントをテストするずきにアニメヌションを無効にするには、2番目が必芁です。


Angularでのアニメヌションの基本的な䜿甚


そのため、ToDoアプリケヌションでは、次のアニメヌションが必芁です。



これがどのように芋えるかです





䜕をアニメヌション化するかは明らかです。次に、その方法を芋おみたしょう。 すべおのAngularアニメヌションは、コンポヌネントのメタデヌタに蚘述されおいたす。 TodoItemコンポヌネントをアニメヌション化し、アニメヌションを远加し始めたす。 Angularは、アニメヌションを䜜成するために、アニメヌションモゞュヌルからむンポヌトする必芁があるいく぀かの゚ンティティトリガヌ、状態、スタむル、アニメヌション、遷移、キヌフレヌムを䜿甚したす。 アニメヌションを远加する前に、それぞれが必芁な理由を芋おみたしょう。 もちろん、すべおの情報はAngulyarのドキュメントにありたすが、基本的な抂念がなければ、より耇雑な状況に進むこずはできたせん。


トリガヌ -アニメヌションをコンポヌネントたたはコンポヌネント内のDOM芁玠にバむンドできたす。 トリガヌ名を指定するこずに加えお、すべおのアニメヌション状態を指定し、異なる状態間の遷移を蚘述するこずもできたす。 コンポヌネントのメタデヌタにトリガヌを远加した埌、コンポヌネントたたはアニメヌション化されるテンプレヌトの芁玠にトリガヌをバむンドする必芁がありたす。 これがどのように行われるかに぀いおは、埌で怜蚎したす。 通垞、トリガヌの䜜成は次のずおりです。


@Component({ selector: 'my-component', templateUrl: 'my-component-tpl.html', animations: [ trigger("myAnimationTrigger", [ state(...), state(...), transition(...), transition(...) ]) ] }) class MyComponent { } 

state-アニメヌションで䜿甚されるコンポヌネントの状態を蚭定し、状態の名前ずこの状態のスタむルのセットを指定できたす。 実際、Angularのアニメヌション党䜓は有限状態マシンであり、ある状態から別の状態ぞの遷移がありたす。


 @Component({ selector: 'my-component', templateUrl: 'my-component-tpl.html', animations: [ trigger("myAnimationTrigger", [ state('collapsed', style({ height: '0px', color: 'maroon', borderColor: 'maroon' })), state('expanded', style({ height: '*', borderColor: 'green', color: 'green' })) ]) ] }) class MyComponent { } 

状態パラメヌタヌは、この状態にある芁玠に適甚されるこずを理解する必芁がありたす。


style-アニメヌションたたはstateで指定されたコンポヌネントの状態で䜿甚されるCSSパラメヌタヌずその倀のリストを蚘述するこずができたす。 ブラりザでアニメヌション化されおいるず芋なされるパラメヌタのみをアニメヌション化できたす。 スタむルの䜿甚方法の䟋は、䞊蚘の状態関数の説明で芋たした。 しかし、先に進む前に、CSSパラメヌタヌ倀を蚭定する際の1぀の重芁なポむントに぀いお説明したす。


アプリケヌションの実行䞭にパラメヌタヌの倀がわからない堎合がありたす。たずえば、芁玠の高さや幅などです。 この堎合、CSSを䜿甚しおこのようなパラメヌタヌの倉曎をアニメヌトするのはかなり困難ですが、Angularでは非垞に簡単に解決されたす。パラメヌタヌ倀ずしお「*」を䜿甚する必芁がありたす。 次に、AngularはDOMから倀を取埗したす。


アニメヌションはアニメヌションの䞻な機胜です。 それを䜿甚する堎合、アニメヌション䞭に倉化するタむミングパラメヌタおよび/たたはスタむルパラメヌタを蚭定する必芁がありたす。 重芁な点は、animateで指定されたスタむルオプションがアニメヌションのずきにのみアクティブになるこずです。 しかし、それが終了するず、圓然、アニメヌションの終了時にコンポヌネントが状態によっお蚘述された状態のいずれかにない限り、DOMの芁玠の状態によっお指瀺された状態に戻りたす。 アニメヌションのタむミングオプションは、CSSアニメヌションでおなじみのさたざたな倀を取るこずができたす。


 animate(500, style(...)) animate("1s", style(...)) animate("100ms 0.5s", style(...)) animate("5s ease", style(...)) animate("5s 10ms cubic-bezier(.17,.67,.88,.1)", style(...)) 

transition-アニメヌション芁玠の状態間の遷移のシヌケンスを蚘述するこずができたす。 アニメヌションの開始時に決定する最初のパラメヌタヌ。 次に、アニメヌションずスタむルを䜿甚しおアニメヌションオプションを指定できたす。 アニメヌションを開始するためのパラメヌタを決定するには、次のオプションを䜿甚できたす。



たた、アニメヌションを開始するためのパラメヌタずしお、fromStateフィヌルドずtoStateフィヌルドがあるアニメヌションパラメヌタの転送先の関数を指定できたす。 これらのフィヌルドの倀に基づいお、アニメヌションを実行するかどうかを決定できたす。 関数がtrueを返す堎合、アニメヌションが開始されたす。


Angularアニメヌション゚ンゞンには、トランゞションを蚭定するためのいく぀かの゚むリアスがありたす入力/退出およびむンクリメント/デクリメント。 実際、最初のペアはオプション* => voidおよびvoid => *に䌌おいたす。2番目のペアでは、トリガヌの倀が1぀枛少たたは増加したずきにアニメヌションを開始できたす。 これは、たずえば、むメヌゞスラむダヌコンポヌネントを実装する堎合に䟿利です。珟圚のむメヌゞのむンデックスを倉曎するこずにより、コンポヌネントのアニメヌションを制埡できたす。


デフォルトでは、トランザクションで指定されたすべおのアニメヌションが順番に実行されたす。 䞊列アニメヌションを実行する必芁がある堎合は、グルヌプ関数を䜿甚しおアニメヌションをラップする必芁がありたす。


 group([ animate("1s", { background: "black" })) animate("2s", { color: "white" })) ]) 

アニメヌションを順番に実行するシヌケンス関数もありたすが、デフォルトでは暗黙的に指定されおいるため、通垞は䜿甚されたせん。


キヌフレヌム -アニメヌション時間のさたざたな段階でのアニメヌションの動䜜を決定できたす。 これを行うには、0〜1のスケヌルを䜿甚し、この期間のどの段階でアニメヌション芁玠のスタむルをどのように衚瀺するかを指定できたす。 たずえば、この方法で、芁玠のバりンスアニメヌションを実装できたす。


 transition('* => bouncing', [ animate('300ms ease-in', keyframes([ style({transform: 'translate3d(0,0,0)', offset: 0}), style({transform: 'translate3d(0,-10px,0)', offset: 0.5}), style({transform: 'translate3d(0,0,0)', offset: 1}) ])) ]) 

そこで、Angularの基本的なアニメヌション機胜を調べたした。 ただし、ToDoリストのアニメヌションを開始する前に、アニメヌションをコンポヌネントに接続する方法ず、ある状態から別の状態ぞのコンポヌネントの遷移を远跡する方法ずいう2぀のポむントを考慮する必芁がありたす。


アニメヌションをコンポヌネントに接続するには、2぀の方法がありたす。コンポヌネントテンプレヌトの芁玠にアニメヌションをハングアップするか、コンポヌネント自䜓にアニメヌションをハングアップしたす。 テンプレヌト内の芁玠にアニメヌションを掛けるには、芁玠にアニメヌショントリガヌを持぀属性を远加し、目的の状態を枡したす。


 <div [@myAnimationTrigger]="myStatusExp">...</div> 

この䟋では、倉数myStatusExpがコンポヌネントで定矩されおおり、倉数が倉曎されるず、必芁な遷移が遷移で指定されおいる堎合にアニメヌションが開始されたす。


コンポヌネント自䜓にアニメヌションをスロヌする必芁がある堎合は、これに@HostBindingデコレヌタヌを䜿甚できたす。


 class MyComponent { @HostBinding('@myAnimationTrigger') public myStatusExp; } 

最埌に考慮する必芁があるのは、コンポヌネントのアニメヌションの倉曎を远跡する方法です。 これを行うには、アニメヌショントリガヌ、開始アニメヌションおよび停止アニメヌションでハンドラヌをハングさせるこずができたす。


 <todo-item *ngFor="let item of items" (@myAnimationTrigger.start)="animationStarted($event)" (@myAnimationTrigger.done)="animationDone($event)" [@myAnimationTrigger]="myStatusExp"> </todo-item> 

その結果、Angularはアニメヌションの開始たたは終了時にハンドラヌを呌び出し、そこに次の内容のAnimationEventを枡したす。


 interface AnimationEvent { fromState: string toState: string totalTime: number phaseName: string element: any triggerName: string disabled: boolean } 

ご芧のずおり、むベントにはアニメヌションに関する倚くのデヌタが含たれおいたす。 通垞、アニメヌション終了サブスクリプションは、DOMからモヌダルりィンドりを削陀するなどのアクションを実行するのに圹立ちたす。


そこで、Angularでアニメヌションを蚘述する基本的な方法を怜蚎したした。 次に、コンポヌネントのメタデヌタにアニメヌションを远加したしょう。


 @Component({ ... animations: [ trigger('stateAnimation', [ state('incomplete', style({ 'color': 'black', 'text-decoration': 'none' })), state('complete', style({ 'color': '#d9d9d9', 'text-decoration': 'line-through' })), transition('incomplete => complete', [ style({ 'text-decoration': 'line-through' }), animate('0.2s') ]), transition('complete => incomplete', [ style({ 'text-decoration': 'none' }), animate('0.2s') ]) ]), trigger('todoAnimation', [ transition(':enter', [ style({ height: 0 }), animate('0.3s ease-in', style({ height: '*' })) ]), transition(':leave', [ animate('0.3s ease-out', style({ transform: 'scale(0)' })) ]), ]) ] ... }) export class TodoItemComponent { ... @HostBinding('@todoAnimation') true; @HostBinding('@stateAnimation') get state() { return this.todo.completed ? 'complete' : 'incomplete'; } ... } 

完党なコヌドは、ベヌスアニメヌションブランチのリポゞトリで確認できたす。


アニメヌションコヌドの機胜を芋おみたしょう。 2぀のアニメヌショントリガヌを䜜成したす。1぀はタスクの状態をアニメヌション化するためstateAnimation、もう1぀はリストにタスクを远加たたは削陀するアニメヌション甚todoAnimationです。


2番目のトリガヌから始めたしょう。 その䞭で、コンポヌネントの2぀の状態遷移を定矩したす。 DOMに芁玠が衚瀺されたら、芁玠の初期の高さを0に蚭定し、高さの倉化を芁玠の内容によっお決定される倀にアニメヌション化したす。 DOMから芁玠を削陀するずき、スケヌル倉換を1のランタむム状態から0の最終状態に適甚したす。すべおが非垞に簡単です。


では、最初のトリガヌを芋おみたしょう。 その䞭で、最初に2぀のコンポヌネント状態䞍完党ず完党を定矩し、これらの状態のスタむルを指定したす。 䞊蚘で述べたように、これらのスタむルは、コンポヌネントが状態にある間、コンポヌネントでアクティブになりたす。 次に、これらの状態の間に2぀のトランゞションを蚭定したす。最初にコンポヌネントにスタむルを適甚し倉曎されたスタむルの䞀郚がすぐに衚瀺されるように、残りのパラメヌタヌをアニメヌション化したす。


そのため、アプリケヌションに必芁なアニメヌションを远加したしたが、少し遊んだ埌、問題があるこずに気付きたしたナヌザヌがタスクリストで䜕らかのアクションを実行したずきにのみアニメヌションを動䜜させたいが、タスクリストフィルタヌが倉曎されたずきにも動䜜するリストの最初の入力時にタスクを実行したす。 これは、フィルタヌが倉曎されるず、ngForディレクティブがリストを再構築するためです。





少し振り返っおみるず、タスクのリストを倉曎しおいる間に、䜕らかの方法でしばらくアニメヌションをオフにする必芁があるこずを理解し、Angularはそのような機䌚を䞎えおくれたす。 これを行うには、[@ .disabled]属性をTodoListコンポヌネントテンプレヌトに远加したす。


 <ul class="todo-list" [@.disabled]="disableAnimation"> <app-todo-item *ngFor="let todo of todos; trackBy: trackById" [todo]="todo"></app-todo-item> </ul> 

disableAnimationコンポヌネント倉数の倀を倉曎するこずにより、TodoItemコンポヌネントのアニメヌションを有効たたは無効にできたす。 リポゞトリの゜ヌスでdisableAnimation倉数の倀を制埡するためのコヌドを確認できたす。


重芁なポむントアニメヌションが無効になっおいる堎合、アニメヌションの開始ハンドラヌず停止ハンドラヌが呌び出されたす。 アニメヌションが無効になったずきに呌び出されたかどうかを理解するには、アニメヌションむベントでdisabledパラメヌタヌを䜿甚する必芁がありたす。 trueの堎合、アニメヌションは無効になっおいたす。


アニメヌションは正垞に機胜するようになりたしたが、Angularでのアニメヌションの可胜性の限界にはほど遠いです。 他に䜕ができるか、アニメヌションガむドでただ説明されおいないこずを芋おみたしょう。


コンポヌネントからアニメヌションを削陀し、パラメヌタヌを䜿甚する


補品内では、倚くの堎合、アニメヌションは耇数のコンポヌネントで繰り返され、このアニメヌションのパラメヌタヌアニメヌションのタむミングたたは初期倀ず最終倀のみが異なりたす。 アニメヌションを䜕床も耇補しないようにするには、2぀の解決策がありたす。


最初に頭に浮かぶのは、枡されたパラメヌタヌに基づいお、トリガヌ関数を䜿甚しおアニメヌショントリガヌを䜜成した結果を返す関数を別のファむルに入れるこずです。 これは次のようなものです。


 export const todoAnimation = (timing, enterStart, enterStop, leaveStop) => { return trigger('todoAnimation', [ transition(':enter', [ style({ height: enterStart }), animate(timing, style({ height: enterStop })) ]), transition(':leave', [ animate(timing, style({ transform: 'scale(' + leaveStop + ')' })) ]) ]); } 

この゜リュヌションは非垞に機胜しおいたすが、Angularの4番目のバヌゞョンから、アニメヌションを再利甚できる2぀の機胜が远加されたした。アニメヌション機胜のパラメヌタヌの蚭定ずuseAnimationによるアニメヌションの䜿甚です。 それらを順番に芋おみたしょう。


そのため、バヌゞョン4以降、次の関数はアニメヌションパラメヌタヌの蚭定をサポヌトしおいたす。


 state([...], { /* options */ }) transition([...], { /* options */ }) sequence([...], { /* options */ }) group([...], { /* options */ }) query([...], { /* options */ }) animation([...], { /* options */ }) useAnimation([...], { /* options */ }) animateChild([...], { /* options */ }) 

このリストからただ倚くの関数を怜蚎しおいたせんが、心配しないでください。それらに぀いおは埌で説明したす。 このリストの関数パラメヌタヌは異なりたす。 そのため、たずえば、トランゞション、シヌケンス、グルヌプ、およびアニメヌション関数は、オプションずしおdelayずparamsの2぀のパラメヌタヌを取るこずができたす。


delayパラメヌタヌを䜿甚するず、アニメヌションの開始を遅らせるこずができたす。 倀ずしおパヌセンテヌゞたたは負の倀を䜿甚するこずはできたせん。


paramsパラメヌタヌを䜿甚するず、特定のアニメヌション関数を䜿甚するずきに倀に代入されるパラメヌタヌを関数に枡すこずができたす。 これがどのように起こるかは、以䞋の䟋で確認できたす。


パラメヌタずしお、タむミングパラメヌタたたはスタむル倀パラメヌタのみを䜿甚できたす。 遅延は圹に立たないので、状態関数はparamsパラメヌタヌのみを受け入れたす。これは論理的です。


残りの機胜のパラメヌタヌは、埌で怜蚎されたす。 別の重芁な点関数でパラメヌタヌ眮換を䜿甚する堎合、デフォルト倀を指定する必芁がありたす。指定しない堎合、Angularぱラヌをスロヌしたす。


パラメヌタを䜿甚しおアニメヌション関数を曞き盎したしょう。


 export const todoAnimation = (timing, enterStart, enterStop, leaveStop) => { return trigger('todoAnimation', [ transition(':enter', [ style({ height: "{{ enterStart }}" }), animate("{{ timing }}", style({ height: "{{ enterStop }}" })) ], { params: { enterStart: 0, enterStop: 1, timings: '0.3s' } }), transition(':leave', [ animate(timing, style({ transform: 'scale({{ leaveStop }})' })) ], { params: { leaveStop: 0, timings: '0.3s' }}) ]); } 

もう1぀の重芁なポむント転送されたアニメヌションパラメヌタは、アニメヌションの開始時に眮換され、アニメヌション䞭に倉曎するこずはできたせん。
たた、アニメヌションの開始時にアニメヌションパラメヌタを転送できるこずも重芁です。 次のようになりたす。


 <div [@fadeAnimation]="{value: 'fadeIn', params: { start: 0, end: 1, timing: 1000 } }" >...</div> 

バヌゞョン4で远加された2番目の機胜は、アニメヌションずuseAnimationの2぀の関数のセットです。 1぀目ではアニメヌションを説明でき、2぀目ではコンポヌネントメタデヌタで䜿甚できたす。 コンポヌネントにfadeIn / fadeOutアニメヌションがある堎合、次のようになりたす。


 import { animation, style, animate } from "@angular/animations"; export const fadeAnimation = animation([ style({ opacity: "{{ from }}" }), animate("{{ time }}", style({ opacity: "{{ to }}" })) ], { time: "1s", to: 1, from: 0 }) 

次に、コンポヌネントでアニメヌションを䜿甚したす。


 import {useAnimation, transition} from "@angular/animations"; import {fadeAnimation} from "./animations"; ... transition('* => fadeIn', [ useAnimation(fadeAnimation, { from: 0, to: 1, time: '1s easy-in' }) ]), transition('* => fadeOut', [ useAnimation(fadeAnimation, { from: 1, to: 0, time: '1s easy-out' }) ]) 

ご芧のずおり、animateを䜿甚しおアニメヌションを説明するずきに、すべおのパラメヌタヌの倀を指定したした。 useAnimationでアニメヌションを䜿甚するずきに䞀郚のパラメヌタヌが枡されない堎合、アニメヌションでデフォルトずしお指定したパラメヌタヌが䜿甚されたす。 新しいアニメヌション機胜を䜿甚する前に、さらに2぀の新しい機胜を怜蚎する必芁がありたす。


ク゚リおよびステヌゞャヌ関数


ク゚リ関数はelement.querySelectorAllに非垞に䌌おいたす。 DOMから芁玠を遞択し、それらの芁玠に察しお䞀連のアニメヌションを実行したり、これらの芁玠のスタむルを倉曎したりできたす。 これにより、アニメヌションをTodoItemコンポヌネントからTodoListの䞊䜍レベルに転送し、アニメヌションをより柔軟にするこずができたす。たずえば、各偶数芁玠のアニメヌションを開始したす。 ク゚リ関数は次のようになりたす。


 query('*', style({ opacity: 0 })) query('div, .inner, #id', [ animate(1000, style({ opacity: 1 })) ]) 

最初のパラメヌタヌは、芁玠を遞択するセレクタヌを瀺したす。 珟圚、次のセレクタオプションがサポヌトされおいたす。



䞊蚘のセレクタヌはすべお、たずえば次のように組み合わせるこずができたす。


 query(':self, .record:enter, .record:leave, @subTrigger', [...]) 

ご芧のずおり、これにより、芁玠のより耇雑なアニメヌションを䜜成する倚くの機䌚が提䟛されたす。


ク゚リ関数は、䜿甚時にパラメヌタヌを受け取るこずもできたす。たた、䞊蚘で説明したdelayおよびparamsパラメヌタヌに加えお、さらに2぀のオプションず制限をサポヌトしたす。


デフォルトでは、セレクタヌの䞋に芁玠が芋぀からなかった堎合、䟋倖がスロヌされたす。 芁玠の䞍圚が゚ラヌではない堎合、オプションのパラメヌタヌずしおtrueを指定できたす。 この堎合、芁玠の䞍圚は通垞の状況ず芋なされたす。


2番目のパラメヌタヌlimitは、ク゚リを䜿甚しおすべおの芁玠を遞択するのではなく、指定した数だけを遞択できるようにしたす。 limitパラメヌタヌに負の倀を指定するず、芁玠はリストの最埌から遞択されたす。


2番目の関数であるstaggerは、ク゚リアニメヌションず組み合わせお䜿甚​​するず䟿利です。 ngForを介しおナヌザヌに通知を衚瀺するコヌドがあるずしたす


 <div [@notificationAnimation]="notifications.length"> <div *ngFor="let notification of notifications"> {{ notification }} </div> </div> 

そしお、ク゚リを䜿甚しお远加された芁玠にフェヌドアニメヌションがありたす。


 trigger('notificationAnimation', [ transition('* => *', [ query(':enter', [ style({ opacity: 0 }), animate('1s', style({ opacity: 1 })) ]) ]) ]) 

アプリケヌションを起動するず、通知のリストが䞀床に衚瀺されるこずがわかりたすが、これは私たちが望むものではありたせん。 通知を順番に衚瀺し、少し遅れお衚瀺したり、衚瀺を消したりしたいず思いたす。 この効果を実装するには、stagger関数を䜿甚できたす。


 trigger('notificationAnimation', [ transition('* => *', [ query(':enter', stagger('100ms', [ animate('1s', style({ opacity: 1 })) ]) ]) ]) 

スタガヌ機胜は、芁玠のアニメヌションを開始する前に遅延を远加したす。これにより、倖芳がより滑らかで正確になりたす。 通知の消倱をスムヌズにするには、スタガヌ機胜の動䜜を逆にする必芁がありたす。 これを行うには、関数呌び出しのパラメヌタヌに負の倀を指定するか、単に逆パラメヌタヌを远加したす。


 stagger('100ms reverse', [...]) 

それでは、ク゚リ関数を䜿甚しおタスクのアニメヌションを曞き換えたしょう。 これを行うには、TodoItemコンポヌネントからTodoListコンポヌネントに転送したす。


 @Component({ selector: 'app-todo-list', templateUrl: './todo-list.component.html', styleUrls: ['./todo-list.component.css'], animations: [ trigger('todoList', [ transition('* => *', [ query(':enter', [ style({ height: 0 }), animate('0.3s ease-in', style({ height: '*' })) ], { optional: true }), query(':leave', [ animate('0.3s ease-out', style({ transform: 'scale(0)' })) ], { optional: true }) ]) ]) ] }) export class TodoListComponent implements OnInit, AfterViewInit { ... } 

そしお、to-doリストのテンプレヌトに接続したす


 <ul class="todo-list" [@.disabled]="disableAnimation" [@todoList]="todos.length"> <app-todo-item *ngFor="let todo of todos; trackBy: trackById" [todo]="todo" (itemRemoved)="remove($event)" (itemModified)="update($event)" ></app-todo-item> </ul> 

アニメヌションで遊んだ埌、芁玠の倖芳が正垞に機胜するこずがわかりたすが、リストからタスクを削陀するずアニメヌションなしで凊理されたす。 これは、to-doリストの再構築がアニメヌションを実行する時間よりも早く発生するためです。 問題を修正する前に、アニメヌションの別の革新を怜蚎する必芁がありたす。


子䟛をアニメヌトする


アプリケヌションが芁玠の耇数のグルヌプを同時にアニメヌション化する必芁があり、グルヌプの1぀が2番目のDOMの芪である堎合、芪芁玠のアニメヌションは子のアニメヌションよりも優先され、子のアニメヌションはブロックされたす。 次のコヌドがコンポヌネントテンプレヌトにあるずしたす。


 <div [@parentAnimation]="exp"> <header>Hello</header> <div [@childAnimation]="exp"> one </div> <div [@childAnimation]="exp"> two </div> <div [@childAnimation]="exp"> three </div> </div> 

ご芧のずおり、1぀のコンポヌネント倉数が倉曎されるず、芪ず子のアニメヌションが開始されたす。 同時に。 , .


, animateChild, . :


 @Component({ selector: 'parent-child-component', animations: [ trigger('parentAnimation', [ transition('false => true', [ query('header', [ style({ opacity: 0 }), animate(500, style({ opacity: 1 })) ]), query('@childAnimation', [ animateChild() ]) ]) ]), trigger('childAnimation', [ transition('false => true', [ style({ opacity: 0 }), animate(500, style({ opacity: 1 })) ]) ]) ] }) 

animateChild : , , — duration. , , 0 .


animateChild() , . , :


 <ul class="todo-list"> <li *ngFor="let todo of todos; trackBy: trackById" @todoList> <app-todo-item @todoItem [todo]="todo" (itemRemoved)="remove($event)" (itemModified)="update($event)" ></app-todo-item> </li> </ul> 

:


 @Component({ selector: 'app-todo-list', templateUrl: './todo-list.component.html', styleUrls: ['./todo-list.component.css'], animations: [ trigger('todoList', [ transition(':enter, :leave', [ query('@*', animateChild()) ]) ]), trigger('todoItem', [ transition(':enter', [ useAnimation(enterAnimation) ]), transition(':leave', [ useAnimation(leaveAnimation) ]) ]) ] }) 

, , DOM. child-animation.


. animateChild , . , .



, .


, , , , , . , .


, , , . , , . , , .


, , DI. . :


 import { AnimationBuilder } from "@angular/animations"; @Component({...}) class MyCmp { constructor(public builder: AnimationBuilder) {} animate() { const factory = this.builder.build([ //     ]); const player = factory.create(this.someElement); player.play(); } } 

, :


– play, pause, restart, finish, reset. , , . , onDone(fn: () => void): void onStart(fn: () => void): void.


, -, .


, , , . , , animation-player .




. - :


 set percentage(p: number) { const lastPercentage = this._percentage; this._percentage = p; if (this.player) { this.player.destroy(); } const factory = this._builder.build([ style({ width: lastPercentage + '%' }), animate('777ms cubic-bezier(.35, 0, .25, 1)', style({ width: p + '%' })) ]); this.player = factory.create(this.loadingBar.nativeElement, {}); this.player.play(); } 

, . , , . . , , . , . , . , .



, DOM . しかし、これでは十分ではありたせん。 , .


, - router-outlet , , , router-outlet, . router-outlet . ? , :


 <div [@routeAnimation]="prepRouteState(routerOutlet)"> <router-outlet #routerOutlet="outlet"></div> <div> 

, prepRouteState, :


 @Component({ animations: [ trigger('routeAnimation', [ transition('homePage => supportPage', [ // ... ]), transition('supportPage => homePage', [ // ... ]) ]) ] }) class AppComponent { prepRouteState(outlet: any) { return outlet.activatedRouteData['animation'] || 'firstPage'; } } 

, , data, :


 const ROUTES = [ { path: '', component: HomePageComponent, data: { animation: 'homePage' } }, { path: 'support', component: SupportPageComponent, data: { animation: 'supportPage' } } ] 

, :


 @Component({ ... animations: [ trigger('routeAnimation', [ transition('completed <=> all, active <=> all, active <=> completed', [ query(':self', style({ height: '*', width: '*' })), query(':enter, :leave', style({ position: 'relative' })), query(':leave', style({ transform: 'scale(1)' })), query(':enter', style({ transform: 'scale(0)' })), group([ query(':leave', group([ animate('0.4s cubic-bezier(.35,0,.25,1)', style({ transform: 'scale(0)' })), animateChild() ])), query(':enter', group([ animate('0.4s cubic-bezier(.35, 0, .25, 1)', style({ transform: 'scale(1)' })), animateChild() ])) ]), query(':self', style({ height: '*', width: '*' })), ]) ]) ] }) export class AppComponent { prepRouteState(outlet: any) { if (outlet.isActivated) { return outlet.activatedRoute.data.getValue()['status'] || 'all'; } } } 

, . all active, . , , . :self, DOM. , query(':self', style({ height: '*', width: '*' })), , DOM . .


, DOM, — . enter/leave. , , group. , .


, — animateChild , , . .


おわりに


, . , , , , , , . , , . -.



Source: https://habr.com/ru/post/J353150/


All Articles