
äœããã®åœ¢åŒã®ã¢ãã¡ãŒã·ã§ã³ããªããã°ãçé¢ç®ãªã¢ããªã±ãŒã·ã§ã³ã¯ã§ããŸããã ã¢ãã¡ãŒã·ã§ã³ã¯ãã¢ããªã±ãŒã·ã§ã³ãããçŸä»£çã§çŸãããå€ãã®å Žåããçè§£ããããããã¢ããªã±ãŒã·ã§ã³å
ã®ç©ºéã®æ¹åãæ¹åããŸãã ãã£ãŒãããã¯ããªããšãã¢ã€ãã ãã¯ãªãã¯ãããšãã«äœãèµ·ãã£ãã®ããçè§£ããã®ãé£ããå ŽåããããŸãã 以åã¯ãå¿
èŠã«å¿ããŠãã¢ããªã±ãŒã·ã§ã³ã«ã¢ãã¡ãŒã·ã§ã³ã远å ãã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-ã¢ãã¡ãŒã·ã§ã³èŠçŽ ã®ç¶æ
éã®é·ç§»ã®ã·ãŒã±ã³ã¹ãèšè¿°ããããšãã§ããŸãã ã¢ãã¡ãŒã·ã§ã³ã®éå§æã«æ±ºå®ããæåã®ãã©ã¡ãŒã¿ãŒã 次ã«ãã¢ãã¡ãŒã·ã§ã³ãšã¹ã¿ã€ã«ã䜿çšããŠã¢ãã¡ãŒã·ã§ã³ãªãã·ã§ã³ãæå®ã§ããŸãã ã¢ãã¡ãŒã·ã§ã³ãéå§ããããã®ãã©ã¡ãŒã¿ã決å®ããã«ã¯ã次ã®ãªãã·ã§ã³ã䜿çšã§ããŸãã
- transitionïŒ "on => off"ãanimateïŒ...ïŒïŒ-ããªã¬ãŒã 'on'ç¶æ
ãã 'off'ç¶æ
ã«é·ç§»ãããšãã«ã¢ãã¡ãŒã·ã§ã³ãéå§ããŸã
- transitionïŒ "on <=> off"ãanimateïŒ...ïŒïŒ-ç¶æ
'on'ãã 'off'ã«ããŸãã¯ãã®éã«åãæ¿ãããšã¢ãã¡ãŒã·ã§ã³ãéå§ããŸã
- transitionïŒ "* => off"ãanimateïŒ...ïŒïŒ-ä»»æã®ç¶æ
ãããªãã«åãæ¿ãããšãã«ã¢ãã¡ãŒã·ã§ã³ãéå§ããŸãã éæ¹å 'on => *'ã瀺ãããšãã§ããŸãã
- transitionïŒ "void => *"ãanimateïŒ...ïŒïŒ-èŠçŽ ãDOMã«è¿œå ããããšã¢ãã¡ãŒã·ã§ã³ãéå§ããŸãã éãã©ã³ã¶ã¯ã·ã§ã³ã* => voidããæå®ãããšãèŠçŽ ãDOMããåé€ããããšãã«ã¢ãã¡ãŒã·ã§ã³ãéå§ãããŸã
ãŸããã¢ãã¡ãŒã·ã§ã³ãéå§ããããã®ãã©ã¡ãŒã¿ãšããŠã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([...], { }) transition([...], { }) sequence([...], { }) group([...], { }) query([...], { }) animation([...], { }) useAnimation([...], { }) animateChild([...], { })
ãã®ãªã¹ããããŸã å€ãã®é¢æ°ãæ€èšããŠããŸããããå¿é
ããªãã§ãã ããããããã«ã€ããŠã¯åŸã§èª¬æããŸãã ãã®ãªã¹ãã®é¢æ°ãã©ã¡ãŒã¿ãŒã¯ç°ãªããŸãã ãã®ãããããšãã°ããã©ã³ãžã·ã§ã³ãã·ãŒã±ã³ã¹ãã°ã«ãŒããããã³ã¢ãã¡ãŒã·ã§ã³é¢æ°ã¯ããªãã·ã§ã³ãšããŠ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 })) ])
æåã®ãã©ã¡ãŒã¿ãŒã¯ãèŠçŽ ãéžæããã»ã¬ã¯ã¿ãŒã瀺ããŸãã çŸåšã次ã®ã»ã¬ã¯ã¿ãªãã·ã§ã³ããµããŒããããŠããŸãã
- éåžžã®CSSã»ã¬ã¯ã¿ãŒ-å€å
žçãªCSSã»ã¬ã¯ã¿ãŒãã»ã¬ã¯ã¿ãŒãšããŠäœ¿çšã§ããŸããããšãã°ããã®ãããªã¯ãšãªïŒ 'divãïŒidã.classã[attr]ãa + b'ïŒ
- ãšã€ãªã¢ã¹ã®äœ¿çšïŒEnterããã³Leave-Angularã«ãã£ãŠDOMã§è¿œå ãŸãã¯åé€ãããã¢ã€ãã ãéžæã§ããŸã
- @triggerNameãŸãã¯@ *-ç¹å®ã®ããªã¬ãŒãæã€èŠçŽ ããŸãã¯ç¹å®ã®ããªã¬ãŒãæã€ãã¹ãŠã®èŠçŽ ãéžæã§ããŸã
- ïŒã¢ãã¡ãŒã·ã§ã³-çŸåšã¢ãã¡ãŒã·ã§ã³åãããŠãããã¹ãŠã®èŠçŽ ãéžæã§ããŸã
- ïŒself-ã¯ãšãªãåŒã³åºãããèŠçŽ èªäœãéžæã§ããŸã
äžèšã®ã»ã¬ã¯ã¿ãŒã¯ãã¹ãŠãããšãã°æ¬¡ã®ããã«çµã¿åãããããšãã§ããŸãã
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([
, :
â 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 , , . .
ãããã«
, . , , , , , , . , , . -.