Menganimasikan Transisi Rute Sudut

Jared Youtsey | ng-conf | Oktober 2019

Tambahkan gaya ke aplikasi Anda dengan menganimasikan transisi rute Anda!

Untuk artikel ini saya akan menganggap Anda sudah memahami dasar-dasar routing dan komponen Angular. Saya tidak akan membuat Anda bosan dengan membangun seluruh aplikasi. Kami akan langsung menambahkan animasi sehingga Anda dapat melihat hasil langsung!

Kode selesai untuk contoh ini dapat ditemukan di sini .

Tambahkan BrowserAnimationsModule

Di app.module.ts Anda tambahkan BrowserAnimationsModule ke modul imports .

 ... import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ imports: [ ..., BrowserAnimationsModule ], ... }) export class AppModule {}

Catatan Tentang Pengujian Unit

Untuk pengujian unit, impor NoopAnimationsModule sebagai gantinya. Ini memenuhi kontrak sambil mengisolasi unit test dari keharusan berurusan dengan transisi.

Animasi Mempengaruhi Pengalaman Pengguna

Pernahkah Anda melihat presentasi PowerPoint yang memiliki seribu transisi, font, dan warna yang berbeda? Yuck. Ambil pelajaran dan jaga agar transisi Anda tetap sederhana dan konsisten untuk menghindari membingungkan atau membebani pengguna Anda.

Premis

Untuk contoh ini, saya akan menyajikan satu set animasi sederhana yang masuk akal dalam konteks navigasi maju dan mundur. Tampilan dianimasikan ke kiri atau kanan berdasarkan arah navigasi router. Kami akan memiliki tiga komponen bernama OneComponent , TwoComponent , dan ThreeComponent , demi kesederhanaan. Saat menavigasi dari Satu ke Dua , Satu akan meluncur ke kiri sementara Dua akan meluncur masuk dari kanan. Dua hingga Tiga akan melakukan hal yang sama. Saat menavigasi dari Tiga ke Dua , animasi akan dibalik. Selain itu, opasitas tampilan akan dianimasikan saat mereka keluar dan memasuki halaman.

Status, Transisi, dan Pemicu, Astaga!

State adalah definisi gaya statis. Transisi menentukan bagaimana properti dalam gaya akan berubah. Pemicu menentukan tindakan apa yang akan menyebabkan satu keadaan bertransisi ke keadaan lain.

  • Negara = Apa
  • Transisi = Bagaimana
  • Pemicu = Kapan
  • "animasi" = Transisi yang dipicu dari satu keadaan ke keadaan lainnya.

Konfigurasi Router

Untuk menghubungkan animasi ke router, kita harus menambahkan data ke konfigurasi rute. Berikut adalah rute kami yang dimodifikasi:

 const routes: Routes = [ { path: '', children: [ { path: 'one', component: OneComponent, data: { animationState: 'One' } }, { path: 'two', component: TwoComponent, data: { animationState: 'Two' } }, { path: 'three', component: ThreeComponent, data: { animationState: 'Three' } }, { path: '**', redirectTo: 'one' } ] }, { path: '**', redirectTo: 'one' } ];

Nama animationState bersifat arbitrer. Tapi, Anda harus melacak apa yang Anda gunakan. Saya telah menggunakan nama ini karena kita mendefinisikan apa yang negara animasi mewakili rute ini. Negara = Apa.

Konfigurasi Komponen Aplikasi

Mulailah dengan mengonfigurasi AppComponent untuk menyiapkan animasi untuk perubahan rute. Di app.component.ts tambahkan metode:

 prepareRoute(outlet: RouterOutlet) { return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animationState']; }

Perhatikan pemeriksaan rute dengan data untuk properti yang ditentukan status, animationState .

Sekarang, hubungkan template. Pertama, mari tambahkan variabel template sehingga kita bisa mendapatkan referensi ke <router-outlet> .

 <router-outlet #outlet="outlet"></router-outlet>

Selanjutnya, tambahkan properti sintetis ke elemen container <router-outlet> . Sangat penting bahwa itu berada di div wadah, bukan di <router-outlet> itu sendiri. Nama properti sintetis ini bersifat arbitrer, tetapi sebaiknya dipahami bahwa nama tersebut akan sesuai dengan nama pemicu animasi. Demi contoh ini, sebut saja triggerName .

 <div [@triggerName]="prepareRoute(outlet)"> <router-outlet #outlet="outlet"></router-outlet> </div>

Kami meneruskan metode prepareRoute dengan argumen outlet variabel template ke properti sintetis @triggerName .

Pada titik ini, jika Anda menjalankan aplikasi, Anda akan menemukan bahwa ada kesalahan di konsol:

 ERROR Error: Found the synthetic property @triggerName. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.

Tapi, tunggu, kita sudah melakukannya?! Angular bingung karena kita belum benar-benar menentukan pemicunya! Jadi, ayo lakukan sekarang.

Tentukan Animasi

Ingat, animasi disebabkan oleh pemicu yang menyebabkan transisi dari satu keadaan ke keadaan lain. Saat kita mendefinisikan animasi, kita mulai dengan pemicu dan bekerja ke dalam definisi itu.

Buat file baru bernama route-transition-animations.ts sebelah app.component.ts . Ini akan berisi definisi pemicu, triggerName , dan transisi dari dan ke status yang ingin kita animasikan.

 import { trigger } from '@angular/animations'; export const routeTransitionAnimations = trigger('triggerName', []);

Di sini kita akhirnya mendefinisikan triggerName ! Argumen array adalah tempat kita akan mendefinisikan transisi.

Sebelum kita mendefinisikan transisi, mari kaitkan app.component.ts ke definisi pemicu:

 ... import { routeTransitionAnimations } from './route-transition-animations'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], animations: [routeTransitionAnimations] }) export class AppComponent {...}

Sekarang, mari kembali dan menyempurnakan transisi pemicu di route-transition-animations.ts .

Angular menggunakan sintaks panah sederhana untuk mendefinisikan transisi dari satu keadaan ke keadaan lainnya. Misalnya, jika kita ingin menangani navigasi dari Satu ke Dua, kita menggunakan One => Two . Jika kita ingin menangani kedua arah, kita dapat menggunakan panah dua arah, One <=> Two , dan kemudian transisi akan diterapkan dari Satu ke Dua dan dari Dua ke Satu .

Angular memiliki beberapa konsep kuat yang telah ditentukan sebelumnya selain status yang disebutkan.

  • void = elemen memasuki atau meninggalkan tampilan.
  • * = keadaan apapun any
  • :enter dan :leave adalah alias untuk transisi void => * dan * => void

Mari kita tinjau animasi yang kita inginkan di awal artikel. One => Two dan Two => Three harus menggeser tampilan sebelumnya ke kiri dan membawa tampilan baru dari kanan. Karena keduanya memiliki transisi yang sama, kedua perubahan status dapat didefinisikan dalam satu transisi menggunakan nilai yang dipisahkan koma:

 import { trigger, transition } from '@angular/animations'; export const routeTransitionAnimations = trigger('triggerName', [ transition('One => Two, Two => Three', []) ]);

Sekarang, untuk transformasi yang sebenarnya! Pertama, perhatikan apa yang dikatakan dokumentasi Angular resmi :

Selama transisi, tampilan baru disisipkan langsung setelah yang lama dan kedua elemen muncul di layar secara bersamaan. Untuk mencegah hal ini, terapkan gaya tambahan ke tampilan host, dan ke tampilan anak yang dihapus dan disisipkan. Tampilan host harus menggunakan pemosisian relatif, dan tampilan turunan harus menggunakan pemosisian absolut . Menambahkan gaya ke tampilan menganimasikan wadah di tempatnya, tanpa DOM memindahkan semuanya.

Terapkan ini ke definisi gaya dengan menambahkan yang berikut ini:

 import { trigger, transition, style, query } from '@angular/animations'; export const routeTransitionAnimations = trigger('triggerName', [ transition('One => Two, Two => Three', [ style({ position: 'relative' }), query(':enter, :leave', [ style({ position: 'absolute', top: 0, right: 0, width: '100%' }) ]) ]) ]);

Pertama, style({ position: 'relative' }) menetapkan gaya pada elemen yang menjadi target pemicu menjadi position: relative . Elemen target adalah elemen dengan properti sintetis @triggerName , yang merupakan div yang berisi <router-outlet> . Sekarang, "tampilan host" menggunakan pemosisian relatif per dokumen resmi.

Selanjutnya, query(':enter, :leave', [...]) . Ini berarti "kueri untuk elemen turunan yang masuk atau keluar dari tampilan". Kemudian menerapkan definisi gaya berikut untuk elemen-elemen tersebut. Saya tidak akan terlalu mendalami solusi CSS untuk posisi tersebut, tetapi kunci sebenarnya adalah kita menyetel elemen turunan ke posisi absolut, sesuai dengan dokumen resmi. CSS Anda hampir pasti akan berbeda pada saat ini berdasarkan gaya animasi yang Anda pilih dan tata letak DOM aplikasi.

Sekarang, kita perlu mendefinisikan transisi individu, secara berurutan. Ini akan mengikuti query pertama dalam argumen array transition

Kueri ini menentukan status awal untuk tampilan yang masuk, memposisikannya dari layar ke paling kanan:

 query(':enter', [style({ right: '-100%', opacity: 0 })]),

Kueri berikutnya memastikan bahwa animasi komponen turunan apa pun yang perlu terjadi pada komponen yang keluar terjadi sebelum tampilan keluar dianimasikan di luar layar:

 query(':leave', animateChild()),

Selanjutnya, kami mengelompokkan cuti dan masuk bersama sehingga transisi ini terjadi bersamaan (jika tidak, yang lama akan pergi, meninggalkan ruang kosong, dan kemudian yang baru akan masuk). Kami animate , yang berarti "transisi gaya yang ada ke gaya yang ditentukan selama periode waktu tertentu dengan fungsi easing". Tampilan keluar menjiwai right menjadi 100% (paling kiri layar) dan animasi masuk right menjadi 0% (paling kanan layar):

 group([ query(':leave', [animate('1s ease-out', style({ right: '100%', opacity: 0 }))]), query(':enter', [animate('1s ease-out', style({ right: '0%', opacity: 1 }))]) ]),

Pada titik ini, tampilan lama telah pergi, yang baru telah masuk, dan kami ingin memicu animasi anak apa pun pada tampilan baru:

 query(':enter', animateChild())

Dan inilah yang terlihat seperti:

Gambar bergerak dari tombol klik mouse. Ada tiga tombol di bagian atas gambar berlabel "Satu", "Dua", dan "Tiga". Ketika mouse mengklik "Satu" sebuah bar merah muda membaca Satu meluncur ke layar, ketika mouse mengklik "Dua" sebuah bar biru membaca Dua slide ke layar, dan ketika mouse mengklik "Tiga" sebuah bar hijau membaca Tiga slide ke layar. Semua bar meluncur dari kanan ke kiri.

Sekarang, tambahkan transisi untuk arah sebaliknya, Three => Two , dan Two => One , setelah transisi pertama, dan ubah right ke left :

 transition('Three => Two, Two => One', [ style({ position: 'relative' }), query(':enter, :leave', [ style({ position: 'absolute', top: 0, left: 0, width: '100%' }) ]), query(':enter', [style({ left: '-100%', opacity: 0 })]), query(':leave', animateChild()), group([ query(':leave', [animate('1s ease-out', style({ left: '100%', opacity: 0 }))]), query(':enter', [animate('1s ease-out', style({ left: '0%', opacity: 1 }))]) ]), query(':enter', animateChild()) ])

Inilah hasilnya:

Gambar bergerak yang sama seperti di atas, hanya arah geser dari bilah berwarna yang telah berubah.

Terlihat bagus! Kami hanya kehilangan dua definisi transisi, One => Three , dan Three => One . Daripada mendefinisikan sesuatu yang berbeda, kami akan menambahkan ini ke yang sudah ada. Tambahkan One => Three ke definisi kanan, dan Three => One ke left . Transisi sekarang terlihat seperti ini:

 transition('One => Two, Two => Three, One => Three', [...]), transition('Three => Two, Two => One, Three => One', [...])

Dan hasilnya:

Gambar untuk posting

Voila! Animasi transisi rute sudut yang berhasil!

Berikut adalah seluruh definisi pemicu/transisi .

Ini hanya menggores permukaan dari apa yang dapat dilakukan dengan animasi Angular. Lihat artikel saya yang lain tentang *ngIf dan *ngFor Animating Angular untuk bersenang-senang dengan animasi Angular!

ng-conf: Bergabunglah dengan kami untuk Konferensi Web Tepercaya

Ayo pelajari dari anggota dan pemimpin komunitas cara terbaik untuk membangun aplikasi web yang andal, menulis kode berkualitas, memilih arsitektur yang dapat diskalakan, dan membuat pengujian otomatis yang efektif. Didukung oleh ng-conf, bergabunglah dengan kami untuk Konferensi Web Tepercaya pada 26 & 27 Agustus 2021 ini.
https://reliablewebsummit.com/

June 8, 2021

codeorayo

Ampuh! Ini rahasia mengembangkan aplikasi secara instan, tinggal download dan kembangkan. Gabung sekarang juga! Premium Membership [PRIVATE] https://premium.codeorayo.com

Leave a Reply

Your email address will not be published. Required fields are marked *