Transition
Vue nabízí dvě vestavěné komponenty, které pomáhají pracovat s přechody a animacemi v reakci na změny stavu:
<Transition>
pro aplikaci animací, když element nebo komponenta vstupuje či vystupuje z DOM. Tomu se věnuje tato stránka.<TransitionGroup>
pro aplikaci animací při vložení elementu nebo komponenty do seznamuv-for
, při odebrání elementu nebo komponenty z tohoto seznamu nebo při jejich přesunu v rámci seznamu. Tím se zabývá další kapitola.
Kromě těchto dvou komponent můžeme ve Vue aplikovat animace také pomocí dalších technik, jako je přepínání CSS tříd nebo stavově řízené animace pomocí bindingu stylů. Tyto další techniky jsou popsány v kapitole Techniky animace.
Komponenta <Transition>
<Transition>
je vestavěná komponenta, což znamená, že je k dispozici v jakékoli šabloně komponenty, aniž by bylo nutné ji registrovat. Lze ji použít k aplikaci vstupních a výstupních animací na elementy nebo komponenty, které jsou jí předány prostřednictvím výchozího slotu. Vstup nebo výstup může být spuštěn jednou z následujících akcí:
- Podmíněné vykreslování přes
v-if
- Podmíněné zobrazení přes
v-show
- Dynamické přepínání komponent přes speciální element
<component>
- Změna speciálního atributu
key
Zde je příklad nejzákladnějšího použití:
template
<button @click="show = !show">Změnit zobrazení</button>
<Transition>
<p v-if="show">Ahoj</p>
</Transition>
css
/* Co tyto třídy znamenají, vysvětlíme vzápětí! */
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
Ahoj
TIP
<Transition>
podporuje jako obsah svého slotu pouze jediný prvek nebo komponentu. Pokud je obsahem komponenta, musí mít také pouze jeden jediný root element.
Když je element v komponentě <Transition>
vložen nebo odebrán, stane se toto:
Vue automaticky zjistí, zda má cílový prvek aplikovány CSS přechody nebo animace. Pokud ano, budou v odpovídajících časech přidány / odebrány některé CSS třídy přechodu.
Pokud existují listenery pro JavaScript události, budou jejich metody v odpovídajících časech provolány.
Pokud nejsou detekovány žádné CSS přechody / animace a nejsou nastaveny žádné JavaScriptové události, operace DOM pro vložení a/nebo odebrání elementů budou provedeny v následujícím animačním snímku prohlížeče.
Přechody založené na CSS
Třídy přechodu
Existuje šest tříd aplikovaných pro přechody vstupu / výstupu.
v-enter-from
: Počáteční stav pro vstup. Je přidána před vložením prvku, odebrána jeden snímek po vložení prvku.v-enter-active
: Aktivní stav pro vstup. Používá se během celé fáze vstupu. Je přidána před vložením prvku a odstraněna po dokončení přechodu/animace. Třída může být použita k definici trvání (duration), zpoždění (delay) a křivky pro zjemnění (easing) pro vstupní přechod.v-enter-to
: Koncový stav pro vstup. Je přidána jeden snímek po vložení prvku (ve stejný okamžik, kdy je odstraněnov-enter-from
) a odstraněna po dokončení přechodu/animace.v-leave-from
: Počáteční stav pro odchod. Je přidána okamžitě po spuštění odchodového přechodu a odstraněna po jednom snímání.v-leave-active
: Aktivní stav pro odchod. Používá se během celé fáze odchodu. Je přidána okamžitě po spuštění odchodového přechodu a odstraněna po dokončení přechodu/animace. Tato třída může být použita k definování trvání, zpoždění a křivky pro odchodový přechod.v-leave-to
: Koncový stav pro odchod. Je přidána jeden snímek po spuštění odchodového přechodu (ve stejný okamžik, kdy je odstraněnov-leave-from
) a odstraněna po dokončení přechodu/animace.
v-enter-active
a v-leave-active
nám pro vstupní / odchodové přechody umožňují specifikovat různé křivky uvolnění, jak uvidíme na příkladu v následujících sekcích.
Pojmenované přechody
Přechod může být pojmenován pomocí vlastnosti name
:
template
<Transition name="fade">
...
</Transition>
Pro pojmenovaný přechod budou jeho přechodové třídy uvozeny místo předpony v
jménem přechodu. Například třída aplikovaná pro výše uvedený přechod bude fade-enter-active
místo v-enter-active
. CSS pro přechod fade
by měl vypadat takto:
css
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
CSS přechody
<Transition>
se nejčastěji používá v kombinaci s nativními CSS přechody, jako v jednoduchém příkladu výše. CSS vlastnost transition
je zkratka, která nám umožňuje specifikovat více různých aspektů přechodu, včetně vlastností, které by měly být animovány, trvání přechodu a easing funkce.
Zde je více pokročilý příklad, který přechází mezi více vlastnostmi s různou dobou trvání a křivkami pro vstup a výstup:
template
<Transition name="slide-fade">
<p v-if="show">Ahoj</p>
</Transition>
css
/*
Animace pro vstup a výstup mohou mít různou
dobu trvání a časování.
*/
.slide-fade-enter-active {
transition: all 0.3s ease-out;
}
.slide-fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
Ahoj
CSS Animace
Nativní CSS animace se používají stejným způsobem jako CSS přechody, s tím rozdílem, že třída *-enter-from
není odstraněna okamžitě po vložení elementu, ale až po události animationend
.
Většinu CSS animací stačí deklarovat pod třídami *-enter-active
a *-leave-active
. Zde je příklad:
template
<Transition name="bounce">
<p v-if="show" style="text-align: center;">
Ahoj, já jsem poskakující text!
</p>
</Transition>
css
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
Ahoj, já jsem poskakující text!
Vlastní třídy přechodu
Předáním následujících vlastností (props) do komponenty <Transition>
můžete specifikovat i své vlastní třídy přechodu:
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
Tyto třídy budou použity místo tříd s výchozími názvy. Obzvlášť užitečné to je, pokud chcete kombinovat přechodový systém Vue s existující knihovnou CSS animací, jako je Animate.css:
template
<!-- předpokládá, že je Animate.css zahrnuto na stránce -->
<Transition
name="custom-classes"
enter-active-class="animate__animated animate__tada"
leave-active-class="animate__animated animate__bounceOutRight"
>
<p v-if="show">Ahoj</p>
</Transition>
Použití přechodů a animací společně
Vue potřebuje připojit event listenery, aby vědělo, kdy přechod skončil. V závislosti na typu použitých CSS pravidel to může být buď transitionend
nebo animationend
. Pokud používáte pouze jeden z nich, Vue automaticky detekuje správný typ.
Nicméně někdy můžete chtít mít na stejném elementu oba, například mít CSS animaci spouštěnou Vue spolu s efektem CSS přechodu při najetí myší. V těchto případech musíte explicitně deklarovat typ, o který se Vue stará, předáním vlastnosti type
s hodnotou buď animation
nebo transition
:
template
<Transition type="animation">...</Transition>
Vnořené přechody a explicitní délky přechodů
Přestože jsou přechodové třídy použity pouze na přímém potomkovi uvnitř <Transition>
, můžeme přecházet na vnořené elementy pomocí vnořených CSS selektorů:
template
<Transition name="nested">
<div v-if="show" class="outer">
<div class="inner">
Ahoj
</div>
</div>
</Transition>
css
/* pravidla aplikovaná na vnořené prvky */
.nested-enter-active .inner,
.nested-leave-active .inner {
transition: all 0.3s ease-in-out;
}
.nested-enter-from .inner,
.nested-leave-to .inner {
transform: translateX(30px);
opacity: 0;
}
/* ... další potřebné CSS vynecháno */
Můžeme dokonce přidat zpoždění přechodu na vnořený prvek při vstupu, což vytvoří posunutou (staggered) animaci vstupu:
css
/* zpoždění vstupu vnořeného prvku pro "staggered" efekt */
.nested-enter-active .inner {
transition-delay: 0.25s;
}
To však vytváří malý problém. Výchozím chováním komponenty <Transition>
je automaticky zjistit, kdy přechod skončil, posloucháním první události transitionend
nebo animationend
na root elementu přechodu. S vnořeným přechodem by však požadovaným chováním mělo být čekání, dokud neskončí i přechody všech vnitřních prvků.
V takových případech můžete specifikovat explicitní dobu přechodu (v milisekundách) pomocí vlastnosti duration
na komponentě <Transition>
. Celková doba by měla odpovídat zpoždění plus době přechodu vnitřního prvku:
template
<Transition :duration="550">...</Transition>
Ahoj
Pokud je to nutné, můžete specifikovat i samostatné hodnoty pro dobu trvání při vstupu a odchodu pomocí objektu:
template
<Transition :duration="{ enter: 500, leave: 800 }">...</Transition>
Úvaha o výkonu
Můžete si všimnout, že animace zobrazené výše využívají převážně vlastnosti jako transform
a opacity
. Tyto vlastnosti jsou efektivní pro animaci, protože:
Neovlivňují layout dokumentu během animace, takže nevyvolávají nákladné výpočty CSS layoutu při každém snímku animace.
Většina moderních prohlížečů může využít hardwarovou akceleraci GPU během
transform
animace.
Naopak vlastnosti jako height
nebo margin
vyvolají změnu CSS layoutu, takže jsou na animaci mnohem dražší a měly by se používat opatrně.
JavaScript události
Pomocí JavaScriptu se můžete k procesu přechodu připojit pomocí naslouchání událostem na komponentě <Transition>
:
html
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@enter-cancelled="onEnterCancelled"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
@leave-cancelled="onLeaveCancelled"
>
<!-- ... -->
</Transition>
js
// voláno před vložením elementu do DOM
// použijte k nastavení počátečního ("enter-from") stavu
function onBeforeEnter(el) {}
// voláno jeden snímek po vložení elementu
// použijte k zahájení animace přechodu
function onEnter(el, done) {
// volání funkce `done` signalizuje konec přechodu
// volitelné, pokud se používá ve spojení s CSS
done()
}
// voláno po dokončení vstupního přechodu
function onAfterEnter(el) {}
// voláno, když je vstupní přechod zrušen před dokončením
function onEnterCancelled(el) {}
// voláno před odchodem
// většinou byste měli použít pouze metodu leave
function onBeforeLeave(el) {}
// voláno při začátku odchodového přechodu
// použijte k zahájení animace odchodu
function onLeave(el, done) {
// volání funkce `done` signalizuje konec přechodu
// volitelné, pokud se používá ve spojení s CSS
done()
}
// voláno po dokončení odchodového přechodu
// a odebrání elementu z DOM
function onAfterLeave(el) {}
// dostupné pouze pro přechody v rámci v-show
function onLeaveCancelled(el) {}
Tyto metody (hooks) lze použít ve spojení s CSS přechody / animacemi nebo samostatně.
Při použití čistě JavaScriptových přechodů je obvykle vhodné přidat vlastnost (prop) :css="false"
. Tímto Vue explicitně říkáme, aby se přeskočilo automatické detekování CSS přechodů. Kromě toho, že je to trochu výkonnější, to dále zabrání tomu, aby se CSS pravidla do přechodu náhodou vmísila:
template
<Transition
...
:css="false"
>
...
</Transition>
S :css="false"
jsme také plně zodpovědní za řízení konce přechodu. V tomto případě jsou pro metody (hooks) @enter
a @leave
vyžadovány callbacky done
. Jinak budou metody volány synchronně a přechod okamžitě skončí.
Zde je ukázka použití knihovny GSAP k provedení animací. Samozřejmě můžete použít libovolnou jinou animační knihovnu, například Anime.js nebo Motion One:
Znovupoužitelné přechody
Přechody mohou být znovupoužity pomocí systému Vue komponent. Pro vytvoření znovupoužiteného přechodu můžeme vytvořit komponentu, která obaluje komponentu <Transition>
a předává obsah slotu:
vue
<!-- MyTransition.vue -->
<script>
// Logika JavaScriptových metod...
</script>
<template>
<!-- obalit vestavěnou komponentu `Transition` -->
<Transition
name="my-transition"
@enter="onEnter"
@leave="onLeave">
<slot></slot> <!-- předat obsah slotu -->
</Transition>
</template>
<style>
/*
Nutné CSS...
Poznámka: zde se vyhněte se použití `<style scoped>`,
protože se nevztahuje na obsah slotu.
*/
</style>
Nyní může být MyTransition
importována a používána stejně jako vestavěná verze:
template
<MyTransition>
<div v-if="show">Ahoj</div>
</MyTransition>
Přechod ihned při zobrazení
Pokud chcete přechod aplikovat také ihned při počátečním vykreslení prvku, můžete přidat vlastnost appear
:
template
<Transition appear>
...
</Transition>
Přechod mezi elementy
Kromě přepínání pomocí v-if
/ v-show
můžeme mezi dvěma elementy také přecházet s využitím v-if
/ v-else
/ v-else-if
, pokud se ujistíme, že je v každém okamžiku zobrazen pouze jeden prvek:
template
<Transition>
<button v-if="docState === 'saved'">Editovat</button>
<button v-else-if="docState === 'edited'">Uložit</button>
<button v-else-if="docState === 'editing'">Zrušit</button>
</Transition>
Klikněte pro změnu stavu:
Režimy přechodu
V předchozím příkladu byly vstupující a odcházející prvky animovány současně a museli jsme je nastavit na position: absolute
, abychom se vyhnuli problému s layoutem, když jsou v DOM přítomny oba prvky.
To však v některých případech není možné nebo to jednoduše není požadované chování. Můžeme chtít, aby odcházející prvek byl nejprve animován pryč a vstupující prvek byl vložen až po dokončení animace odcházejícího prvku. Manuální orchestrace takových animací by byla velmi složitá - naštěstí můžeme toto chování povolit předáním vlastnosti (prop) mode
do <Transition>
:
template
<Transition mode="out-in">
...
</Transition>
Zde je předchozí demo s mode="out-in"
:
Klikněte pro změnu stavu:
<Transition>
také podporuje mode="in-out"
, i když se používá mnohem méně často.
Přechod mezi komponentami
<Transition>
může být také použita nad dynamickou komponentou:
template
<Transition name="fade" mode="out-in">
<component :is="activeComponent"></component>
</Transition>
Komponenta A
Dynamické přechody
Vlastnosti <Transition>
jako name
mohou být také dynamické! To nám umožňuje používat různé přechody operativně na základě změny stavu:
template
<Transition :name="transitionName">
<!-- ... -->
</Transition>
Může to být užitečné, pokud jste definovali přechody / animace pomocí konvenčních tříd Vue přechodů a chcete mezi nimi přepínat.
Můžete také aplikovat různé chování v JavaScriptových metodách pro přechod na základě aktuálního stavu vaší komponenty. V neposlední řadě, nejlepší způsob vytváření dynamických přechodů je pomocí znovupoužitelných přechodů, komponent, které přijímají vlastnosti (props) pro změnu povahy použitých přechodů. Možná to zní trochu kýčovitě, ale opravdu jediným omezením je vaše představivost.
Přechody s atributem key
Někdy si potřebujete vynutit nové vykreslení DOM elementu, aby se přechod spustil.
Například si vezměte tuto komponentu počítadla:
vue
<script setup>
import { ref } from 'vue';
const count = ref(0);
setInterval(() => count.value++, 1000);
</script>
<template>
<Transition>
<span :key="count">{{ count }}</span>
</Transition>
</template>
Pokud bychom atribut key
vynechali, aktualizoval by se pouze textový uzel, a proto by nedošlo k žádnému přechodu. Ovšem s nadefinovaným unikátném key
Vue umí vytvořit nový element span
, kdykoliv se změní hodnota count
, a tak má komponenta Transition
dva různé elementy, mezi kterými lze přechod provést.
Související