<Transition> menganimasikan satu elemen saat masuk ke halaman atau keluar dari halaman, dan <TransitionGroup> melakukannya untuk setiap item sebuah daftar. Vue sendiri gak menggambar animasinya. Dia memasang class CSS di setiap tahap, CSS-mu yang menggerakkan, dan saat elemen keluar, Vue menunggu gerakannya selesai sebelum membuangnya. Bayangin papan kecil "Masuk keranjang!" di Warung Bu Sri. Kalau papannya langsung muncul lalu langsung hilang, pembeli gak sempat sadar. Jadi Bu Sri mengangkatnya pelan-pelan, menahannya sebentar, menurunkannya pelan-pelan, dan baru menyimpannya setelah papannya benar-benar turun.
🧪 Tebakan cepat:
<p v-if="tampil">dibungkus<Transition name="fade">, dengan CSS fade 0,3 detik. Begitutampiljadifalse, berapa lama<p>itu masih ada di DOM: langsung hilang, atau sekitar 0,3 detik? Tebak dulu, jawabannya ada di bagian "Class di setiap tahap".
Transition: satu elemen masuk dan keluar
Toast "Masuk keranjang" yang muncul tiap kali Tambah diklik, lalu hilang sendiri setelah 2 detik:
<script setup>
import { ref } from "vue"
const toast = ref("")
let timer
function tambah(nama) {
toast.value = "Masuk keranjang: " + nama
clearTimeout(timer)
timer = setTimeout(() => (toast.value = ""), 2000)
}
</script>
<template>
<button @click="tambah('Nasi Goreng')">Tambah Nasi Goreng</button>
<Transition name="fade">
<p v-if="toast" class="toast">{{ toast }}</p>
</Transition>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
<Transition>komponen bawaan Vue, jadi gak perlu di-import.- Isinya satu elemen atau komponen yang muncul dan hilang lewat
v-if,v-show, atau:keyyang berganti. name="fade"menentukan awalan class-nya:fade-enter-from,fade-leave-to, dan seterusnya. Tanpaname, awalannyav-:v-enter-from.
Class di setiap tahap
Ini urutan class di <p> yang tercatat di Chrome dengan CSS di atas:
| Waktu | Kejadian | Class di <p> |
|---|---|---|
| 0 ms | toast terisi, <p> dimasukkan ke DOM |
fade-enter-from fade-enter-active |
| 1 frame | fade-enter-active fade-enter-to |
|
| 300 ms | transisinya selesai | class transisi dilepas |
| 2 detik | toast dikosongkan |
fade-leave-from fade-leave-active |
| 1 frame | fade-leave-active fade-leave-to |
|
| 300 ms kemudian | <p> dibuang dari DOM |
enter-fromkeadaan awal saat masuk (di siniopacity: 0),enter-tokeadaan akhirnya (gaya biasa elemen itu),enter-activeterpasang sepanjang proses dan membawatransition-nya.leave-from,leave-active, danleave-tocerminannya untuk keluar.- Vue membaca durasi
transitiondari CSS-nya lalu menunggu. Jadi setelahtoastkosong,<p>masih ada di DOM sekitar 300 ms, sambil memudar. Itu jawaban tebakannya. - Tanpa CSS, class-class itu datang dan pergi dalam satu-dua frame. Elemennya muncul dan hilang seketika, tanpa error.
mode="out-in": ganti satu elemen dengan yang lain
Kalau isi toast berganti dari Nasi Goreng ke Es Teh dengan <p :key="toast">, Vue menganggapnya elemen baru: yang lama keluar, yang baru masuk. Defaultnya keduanya jalan bersamaan, jadi selama 300 ms ada dua <p> di DOM dan tata letaknya melompat. <Transition name="fade" mode="out-in"> membuat yang lama keluar dulu sampai selesai, baru yang baru masuk.
v-if dan v-else di dalam satu <Transition> juga boleh, karena yang dirender tetap cuma satu.
TransitionGroup: daftar keranjang
<TransitionGroup name="list" tag="ul">
<li v-for="item in keranjang" :key="item.id">{{ item.nama }}</li>
</TransitionGroup>
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
.list-move {
transition: transform 0.3s ease;
}
.list-leave-active {
position: absolute;
}
tag="ul"membuat<ul>sungguhan di sekeliling item-itemnya. Tanpatag, gak ada elemen pembungkus. Atribut sepertiiddi<TransitionGroup>jatuh ke<ul>itu.- Setiap item wajib punya
:keyyang unik. Tanpa key, build development menulis[Vue warn]: <TransitionGroup> children must be keyed. - Class
list-movedipasang di item yang bergeser posisinya.position: absolutedilist-leave-activemengangkat item yang keluar dari alur halaman, jadi item lain bisa langsung naik dengan mulus.
Keranjang berisi Nasi Goreng, Mie Ayam, Es Teh, lalu Nasi Goreng dihapus:
:key |
Yang terlihat selama 300 ms |
|---|---|
item.id |
Nasi Goreng memudar ke kanan, Mie Ayam dan Es Teh bergeser naik dengan list-move |
| gak ada | baris pertama langsung jadi Mie Ayam, baris kedua jadi Es Teh, dan baris ketiga yang memudar |
Tanpa key, Vue memakai ulang elemen menurut urutan, mengganti teksnya, lalu membuang elemen terakhir. Animasinya jalan di baris yang salah.
Di editor latihan
Latihan pertama ditulis sebagai file .vue utuh, seperti di proyek Vite: <script setup>, <template>, dan <style>, dan CSS di <style> ikut dipasang di pratinjau. Format ---template--- yang dipakai Playground di Lab gak punya blok <style>: <style> di template dibuang diam-diam. Karena itu kode Playground di Lab memasang CSS-nya lewat script:
document.getElementById("gaya-transisi")?.remove()
const gaya = document.createElement("style")
gaya.id = "gaya-transisi"
gaya.textContent = ".fade-enter-active, .fade-leave-active { transition: opacity 0.3s } .fade-enter-from, .fade-leave-to { opacity: 0 }"
document.head.appendChild(gaya)
- Latihan pertama:
<button id="toggle">Toggle</button>membalikshow, dan<p id="animated">Animated!</p>tampil saatshowbernilaitrue, dibungkus<Transition name="fade">, dengan fade 0,3 detik di<style>. Sesaat setelah klik, pemeriksanya melihat paragrafnya masih ada dengan classfade-leave-active, artinya sedang memudar. Untuk memastikan paragrafnya akhirnya hilang, pemeriksanya menunggu animasi yang dimulai klik itu selesai (paling lama 2 detik), sepertiawaitdi test. - Latihan kedua: daftar mulai dari
"Item 1"dan"Item 2",<span id="total">berisi2. Klik#add-itemmenambah"Item 3"ke daftarnya, dan total jadi3. Daftarnya ditulis<TransitionGroup tag="ul" id="anim-list">dengan:key="item"di tiap<li>.
⚠️ Jebakan yang sering ketemu
v-ifdi<Transition>, bukan di elemennya.<Transition v-if="tampil">membuang seluruh Transition, jadi gak ada yang menjalankan animasi keluar dan elemennya hilang seketika. Taruhv-ifdi elemen di dalamnya.- Dua elemen di satu
<Transition>. Cuma elemen pertama yang dirender. Build development menulis[Vue warn]: <transition> can only be used on a single element or component. Use <transition-group> for lists.Pakaiv-if/v-else, atau<TransitionGroup>. - Nama class gak cocok.
name="fade"mencari.fade-enter-active; CSS bernama.v-enter-activegak terpakai, dan elemennya muncul tanpa animasi. - Teks dan angka di latihan. Tombolnya harus memakai
@click, tampilnya diaturv-ifatauv-showdarirefdi dalam<Transition>, item barunya bernamaItem 3di dalam<TransitionGroup>, dan#totalberubah dari2jadi3.
TL;DR: <Transition name="fade"> membungkus satu elemen yang muncul dan hilang lewat v-if, v-show, atau :key. Vue memasang fade-enter-from, fade-enter-active, fade-enter-to saat masuk dan fade-leave-from, fade-leave-active, fade-leave-to saat keluar; CSS-mu yang menggerakkan, dan elemen yang keluar baru dibuang setelah transisinya selesai. mode="out-in" membuat yang lama keluar dulu sebelum yang baru masuk. <TransitionGroup tag="ul"> menganimasikan setiap item daftar, wajib dengan :key unik, dan class -move menggeser item yang berpindah. Taruh v-if di elemen, bukan di Transition-nya.