Dies ist der fünfte Teil einer fünfteiligen Reihe über das JavaScript-Framework Vue.js. In diesem letzten Teil der Reihe behandeln wir Animationen (wenn Sie mich kennen, wussten Sie das wahrscheinlich schon). Dies ist keine vollständige Anleitung, sondern vielmehr ein Überblick über die Grundlagen, um Ihnen den Einstieg zu erleichtern, damit Sie Vue.js kennenlernen und verstehen können, was das Framework zu bieten hat.

Artikelserie
- Rendering, Direktiven und Ereignisse
- Komponenten, Props und Slots
- Vue-cli
- Vuex
- Animationen (Sie sind hier!)
Einige Hintergründe
Es gibt integrierte <transition> und <transition-group> Komponenten, die sowohl CSS- als auch JS-Hooks ermöglichen. Wenn Sie von React kommen, wird Ihnen das Konzept der Transition-Komponente vertraut sein, da sie in Bezug auf Lifecycle Hooks ähnlich wie ReactCSSTransitionGroup funktioniert, aber einige bemerkenswerte Unterschiede aufweist, die Nerds wie mich begeistern.
Wir beginnen mit CSS-Übergängen, dann fahren wir mit CSS-Animationen fort, dann besprechen wir JS-Animations-Hooks und dann das Animieren mit Lifecycle-Methoden. Der Übergang von Zuständen liegt außerhalb des Rahmens dieses Artikels, ist aber möglich. Hier ist ein gut kommentierter Pen, den ich gemacht habe, der genau das tut. Ich könnte wahrscheinlich auch dazu überredet werden, diesen Artikel zu schreiben, sobald ich mich lange ausgeruht habe.
Übergänge vs. Animationen
Nur für den Fall, dass Sie verwirrt sind, warum Übergänge und Animationen unterschiedliche Abschnitte in diesem Artikel haben, lassen Sie mich erklären, dass sie, obwohl sie ähnlich klingen, etwas anders sind. Ein Übergang funktioniert im Grunde, indem Werte von einem Zustand in einen anderen interpoliert werden. Wir können damit großartige Dinge tun, aber sie sind eher einfach. Von hier nach dort und wieder zurück.
Animationen sind etwas anders, da Sie mehrere Zustände innerhalb einer Deklaration festlegen können. Zum Beispiel könnten Sie einen Keyframe 50 % in die Animation setzen und dann kann bei 70 % etwas völlig anderes passieren und so weiter. Sie können sogar viele Animationen mit Verzögerungen verketten, um wirklich komplexe Bewegungen zu erzielen. Animationen können sich wie Übergänge *verhalten*, bei denen wir nur etwas von hier nach dort interpolieren, aber Übergänge können keine mehreren Schritte wie eine Animation haben (nicht ohne einige verrückte, hacky Entwicklungen, wofür sie eigentlich nicht gedacht sind).
Was die Werkzeuge angeht, sind beide nützlich. Betrachten Sie Übergänge als Säge und Animationen als Kettensäge. Manchmal müssen Sie nur eine Sache sägen und es wäre albern, teure Ausrüstung zu kaufen. Für robustere Projekte ist es sinnvoller, in die Kettensäge zu investieren.
Jetzt, da wir diese Grundlagen verstanden haben, sprechen wir über Vue!
CSS-Übergänge
Nehmen wir an, wir haben ein einfaches Modal. Das Modal wird bei einem Klick auf einen Button angezeigt und ausgeblendet. Basierend auf den vorherigen Abschnitten wissen wir bereits, dass wir Folgendes tun könnten: eine Vue-Instanz mit einem Button erstellen, eine Kindkomponente aus dieser Instanz erstellen, die Daten im Zustand festlegen, sodass sie eine Art Booleschen Wert umschaltet, und einen Event-Handler hinzufügen, um diese Kindkomponente anzuzeigen und auszublenden. Wir könnten v-if oder v-show verwenden, um die Sichtbarkeit umzuschalten. Wir könnten sogar einen Slot verwenden, um den Button-Toggle in das Modal einzufügen.
<div id="app">
<h3>Let's trigger this here modal!</h3>
<button @click="toggleShow">
<span v-if="isShowing">Hide child</span>
<span v-else>Show child</span>
</button>
<app-child v-if="isShowing" class="modal">
<button @click="toggleShow">
Close
</button>
</app-child>
</div>
<script type="text/x-template" id="childarea">
<div>
<h2>Here I am!</h2>
<slot></slot>
</div>
</script>
const Child = {
template: '#childarea'
};
new Vue({
el: '#app',
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
},
components: {
appChild: Child
}
});
Siehe den Pen von Sarah Drasner.
Das funktioniert, aber es ist ziemlich erschreckend, dass dieses Modal einfach in unser Gesicht poppt. 😳
Wir montieren und demontieren diese Kindkomponente bereits mit v-if, sodass Vue uns Änderungen an diesem Ereignis verfolgen lässt, wenn wir diese Bedingung in eine Transition-Komponente einwickeln.
<transition name="fade">
<app-child v-if="isShowing" class="modal">
<button @click="toggleShow">
Close
</button>
</app-child>
</transition>
Nun könnten wir einfach <transition> aus der Box heraus verwenden. Dies gibt uns ein v- Präfix für einige Transition-Hooks, die wir in unserem CSS verwenden können. Es bietet enter/leave, was die Position ist, mit der die Animation im ersten Frame beginnt, enter-active/leave-active, während die Animation läuft – dies ist die Klasse, auf der Sie die Animationseigenschaften selbst anwenden, und enter-to/leave-to, die angibt, wo sich das Element im letzten Frame befinden soll.
Ich werde eine Grafik aus der Dokumentation verwenden, um dies zu zeigen, da ich denke, dass sie die Klassen so schön und klar wie möglich beschreibt.

Persönlich arbeite ich normalerweise nicht mit dem Standard-v-Präfix. Ich gebe der Transition immer einen Namen, damit es keine Kollisionen gibt, wenn ich später eine weitere Animation anwenden möchte. Das ist nicht schwer zu tun, denn wie Sie oben sehen können, haben wir einfach ein name-Attribut zur Transition-Komponente hinzugefügt: name="fade".
Jetzt, da wir unsere Hooks haben, können wir die Transition mit ihnen erstellen.
.fade-enter-active, .fade-leave-active {
transition: opacity 0.25s ease-out;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
Die Klassen .fade-enter-active und .fade-leave-active sind die Stellen, an denen wir die eigentliche Transition anwenden. Das ist normales CSS, Sie können kubische Bézierkurven für Easing, Verzögerungen oder andere Eigenschaften, die überblendet werden sollen, übergeben. Ehrlich gesagt würde dies auch genauso gut funktionieren, wenn Sie die Transition in diesen Klassen auf den Komponentenklassen selbst als Standard anwenden würden. Diese müssen nicht unbedingt durch die Hooks der Transition-Komponente definiert werden. Sie werden einfach dort ruhen und warten, bis sich diese Eigenschaft ändert, und sie zum Überblenden verwenden, wenn sie sich ändert. (Sie benötigen also immer noch die Transition-Komponente und .fade-enter, .fade-leave-to). Der einzige Grund, warum ich sie auf den enter-active- und leave-active-Klassen verwende, ist, dass ich dieselbe Transition auch für andere Elemente wiederverwenden kann und nicht im gesamten Codebasis dieselbe Standard-CSS auf jede Instanz anwenden muss.
Eine weitere Anmerkung: Ich verwende ease-out für beide aktiven Klassen. Das funktioniert und sieht für etwas wie Opazität gut aus. Aber Sie stellen möglicherweise fest, dass Sie bei der Überblendung von Eigenschaften wie transform die beiden trennen möchten und ease-out für die enter-active-Klasse und ease-in für die leave-active-Klasse verwenden (oder kubische Bézierkurven, die vage der gleichen Kurve folgen). Ich finde, das lässt die Animation klassischer aussehen (har har).
Sie sehen, dass wir auch .fade-enter und .fade-to auf opacity: 0 gesetzt haben. Dies werden die erste und letzte Position der Animation sein, der Anfangszustand beim Mounten, der Endzustand beim Demontieren. Sie denken vielleicht, Sie müssen opacity: 1 auf .fade-enter-to und .fade-leave setzen, aber das ist unnötig, da dies der Standardzustand der Komponente ist, also wäre es redundant. CSS-Übergänge und -Animationen verwenden immer den Standardzustand, es sei denn, etwas anderes wird angegeben.
Siehe den Pen von Sarah Drasner.
Das funktioniert gut! Aber was wäre, wenn wir den Hintergrundinhalt ausblenden wollten, damit das Modal im Mittelpunkt steht und der Hintergrund an Fokus verliert? Wir können die <transition>-Komponente nicht verwenden, da diese Komponente auf etwas basiert, das gemountet oder demounted wird, und der Hintergrund einfach dort bleibt. Was wir tun können, ist, Klassen basierend auf dem Zustand zu überblenden und die Klassen zu verwenden, um CSS-Übergänge zu erstellen, die den Hintergrund ändern.
<div v-bind:class="[isShowing ? blurClass : '', bkClass]">
<h3>Let's trigger this here modal!</h3>
<button @click="toggleShow">
<span v-if="isShowing">Hide child</span>
<span v-else>Show child</span>
</button>
</div>
.bk {
transition: all 0.1s ease-out;
}
.blur {
filter: blur(2px);
opacity: 0.4;
}
new Vue({
el: '#app',
data() {
return {
isShowing: false,
bkClass: 'bk',
blurClass: 'blur'
}
},
...
});
Siehe den Pen von Sarah Drasner.
CSS-Animation
Nachdem wir nun verstehen, wie Übergänge funktionieren, können wir auf diesen Kernkonzepten aufbauen, um einige schöne CSS-Animationen zu erstellen. Wir verwenden immer noch die <transition>-Komponente und geben ihr immer noch einen Namen, was uns erlaubt, dieselben Klassen-Hooks zu haben. Der Unterschied hier ist, dass wir anstatt nur den Endzustand festzulegen und zu sagen, wie wir ihn zwischen Anfang und Ende interpolieren wollen, wir @keyframes in CSS verwenden, um lustige und schöne Effekte zu erzielen.
Im letzten Abschnitt haben wir ein wenig darüber gesprochen, wie Sie der Transition-Komponente einen speziellen Namen geben können, den wir dann als Klassen-Hooks verwenden können. In diesem Abschnitt gehen wir noch einen Schritt weiter und wenden unterschiedliche Klassen-Hooks auf verschiedene Abschnitte der Animation an. Sie werden sich erinnern, dass enter-active und leave-active der Ort sind, an dem die ganze spannende Animationsarbeit stattfindet. Wir können unterschiedliche Eigenschaften für jeden dieser Klassen-Hooks festlegen, aber wir können noch einen Schritt weiter gehen und jeder Instanz spezielle Klassen geben.
enter-active-class="toasty"
leave-active-class="bounceOut"
Das bedeutet, dass wir diese Klassen wiederverwenden oder sogar auf Klassen aus CSS-Animationsbibliotheken zugreifen können.
Nehmen wir an, wir möchten, dass ein Ball hineinprallt und herausrollt.
<div id="app">
<h3>Bounce the Ball!</h3>
<button @click="toggleShow">
<span v-if="isShowing">Get it gone!</span>
<span v-else>Here we go!</span>
</button>
<transition
name="ballmove"
enter-active-class="bouncein"
leave-active-class="rollout">
<div v-if="isShowing">
<app-child class="child"></app-child>
</div>
</transition>
</div>
Für das Abprallen bräuchten wir viele Keyframes, wenn wir das in CSS machen wollen (obwohl das in JS eine Codezeile sein könnte). Wir verwenden auch einen SASS-Mixin, um unsere Stile DRY (Don't Repeat Yourself) zu halten. Wir haben auch die Klasse .ballmove-enter bestimmt, damit die Komponente weiß, dass sie außerhalb des Bildschirms beginnen soll.
@mixin ballb($yaxis: 0) {
transform: translate3d(0, $yaxis, 0);
}
@keyframes bouncein {
1% { @include ballb(-400px); }
20%, 40%, 60%, 80%, 95%, 99%, 100% { @include ballb() }
30% { @include ballb(-80px); }
50% { @include ballb(-40px); }
70% { @include ballb(-30px); }
90% { @include ballb(-15px); }
97% { @include ballb(-10px); }
}
.bouncein {
animation: bouncein 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}
.ballmove-enter {
@include ballb(-400px);
}
Beim Herausrollen des Balls sehen Sie, dass wir zwei verschiedene Animationen verschachteln müssen. Das liegt daran, dass die Transformation auf die gesamte Kindkomponente angewendet wird und das Drehen des gesamten Elements zu einer riesigen Rotation führen würde. Also werden wir die Komponente mit einer Translation über den Bildschirm bewegen und den Ball darin mit einer Rotation drehen.
@keyframes rollout {
0% { transform: translate3d(0, 300px, 0); }
100% { transform: translate3d(1000px, 300px, 0); }
}
@keyframes ballroll {
0% { transform: rotate(0); }
100% { transform: rotate(1000deg); }
}
.rollout {
width: 60px;
height: 60px;
animation: rollout 2s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
div {
animation: ballroll 2s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
}
}
Siehe den Pen Ball rollt mit Vue Transition und CSS Animation von Sarah Drasner (@sdras) auf CodePen.
Süße, süße Transitions-Modi
Erinnern Sie sich, als ich sagte, dass Vue wirklich nette süße Kleinigkeiten bei Übergängen bietet, die Nerds wie mich glücklich machen? Hier ist ein kleines Detail, das ich wirklich liebe. Wenn Sie versuchen, eine Komponente hereinzublenden, während eine andere Komponente ausblendet, erhalten Sie diesen wirklich seltsamen Moment, in dem beide gleichzeitig existieren und dann an ihren Platz zurückschnappen (dieses kleine Beispiel aus der Vue-Dokumentation).

Vue bietet Transitions-Modi, die es Ihnen ermöglichen, eine Komponente auszublenden, während eine andere Komponente hereingeladen wird, ohne seltsames Flackern oder Blockieren. Dies geschieht, indem die Übergänge geordnet werden, anstatt sie gleichzeitig stattfinden zu lassen. Es gibt zwei Modi zur Auswahl:
In-out: Das aktuelle Element wartet, bis das neue Element vollständig hineingeblendet ist, bevor es fortfährt.
Out-in: Das aktuelle Element blendet aus, und dann blendet das neue Element ein.
Schauen Sie sich die Demo unten an. Sie sehen den Modus – out-in auf der Transition-Komponente, damit es so aussieht, als würde nur ein Teil umgeblendet.
<transition name="flip" mode="out-in">
<slot v-if="!isShowing"></slot>
<img v-else src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/28963/cartoonvideo14.jpeg" />
</transition>
Siehe den Pen Vue in-out Modi von Sarah Drasner (@sdras) auf CodePen.
Wenn wir diesen Modus entfernen würden, sehen Sie, dass eine Umblendung die andere verdeckt und die Animation holprig aussieht, nicht der Effekt, den wir erzielen wollen.
Siehe den Pen Vue in-out Modi – kein Moduskontrast von Sarah Drasner (@sdras) auf CodePen.
JS-Animation
Wir haben einige schöne JS-Hooks, die sehr einfach zu verwenden oder nicht zu verwenden sind, je nach Bedarf für unsere Animation. Alle Hooks übergeben den el-Parameter (kurz für Element), außer bei den eigentlichen Animations-Hooks enter und leave, die zusätzlich done als Parameter übergeben, welcher, Sie haben es erraten, verwendet wird, um Vue mitzuteilen, dass die Animation abgeschlossen ist. Sie werden feststellen, dass wir auch CSS an einen falsifizierbaren Wert binden, um der Komponente mitzuteilen, dass wir stattdessen JavaScript verwenden werden.
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-Leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
:css="false">
</transition>
Auf grundlegendster Ebene ist dies wirklich alles, was Sie für eine Ein- und Ausblendanimation benötigen, einschließlich der entsprechenden Methoden.
<transition
@enter="enterEl"
@leave="leaveEl"
:css="false">
<!-- put element here-->
</transition>
methods: {
enterEl(el, done) {
//entrance animation
done();
},
leaveEl(el, done) {
//exit animation
done();
},
}
Hier ist ein Beispiel dafür, wie ich dies verwenden würde, um mich in eine GreenSock-Timeline einzuklinken.
new Vue({
el: '#app',
data() {
return {
message: 'This is a good place to type things.',
load: false
}
},
methods: {
beforeEnter(el) {
TweenMax.set(el, {
transformPerspective: 600,
perspective: 300,
transformStyle: "preserve-3d",
autoAlpha: 1
});
},
enter(el, done) {
...
tl.add("drop");
for (var i = 0; i < wordCount; i++) {
tl.from(split.words[i], 1.5, {
z: Math.floor(Math.random() * (1 + 150 - -150) + -150),
ease: Bounce.easeOut
}, "drop+=0." + (i/ 0.5));
...
}
}
});
Siehe den Pen Vue Buchinhaltstypisierung von Sarah Drasner (@sdras) auf CodePen.
Zwei der interessanteren Dinge, die in der obigen Animation zu beachten sind: Ich übergebe {onComplete:done} als Parameter an die Timeline-Instanz, und ich verwende den beforeEnter-Hook, um meinen TweenMax.set-Code einzufügen, der es mir ermöglicht, alle Eigenschaften der Wörter, die ich für die Animation benötige, vor ihrem Eintreten festzulegen, in diesem Fall Dinge wie transform-style: preserve-3d.
Es ist wichtig zu beachten, dass Sie auch das, was Sie für die Animation wünschen, direkt in den CSS als Standardzustand festlegen können. Leute fragen mich manchmal, wie man entscheidet, was in den CSS und was in TweenMax.set gesetzt wird. Als Faustregel gilt: Ich lege im Allgemeinen alle Eigenschaften, die ich speziell für die Animation benötige, in TweenMax.set. Auf diese Weise, wenn sich etwas an der Animation ändert und ich es aktualisieren muss, ist es bereits Teil meines Workflows.
Animationen in Lifecycle-Hooks
Das alles ist wirklich schön, aber was passiert, wenn Sie etwas sehr Komplexes animieren müssen, etwas, das mit einer Menge DOM-Elementen funktioniert? Dies ist eine wirklich gute Zeit, einige Lifecycle-Methoden zu verwenden. In der folgenden Animation haben wir sowohl die <transition>-Komponente als auch die mounted()-Methode verwendet, um einige Animationen zu erstellen.
Siehe den Pen Vue Weather Notifier von Sarah Drasner (@sdras) auf CodePen.
Wenn wir ein einzelnes Element überblenden, verwenden wir die Transition-Komponente, zum Beispiel, wenn der Strich um den Telefon-Button erscheint.
<transition
@before-enter="beforeEnterStroke"
@enter="enterStroke"
:css="false"
appear>
<path class="main-button" d="M413,272.2c5.1,1.4,7.2,4.7,4.7,7.4s-8.7,3.8-13.8,2.5-7.2-4.7-4.7-7.4S407.9,270.9,413,272.2Z" transform="translate(0 58)" fill="none"/>
</transition>
beforeEnterStroke(el) {
el.style.strokeWidth = 0;
el.style.stroke = 'orange';
},
enterStroke(el, done) {
const tl = new TimelineMax({
onComplete: done
});
tl.to(el, 0.75, {
strokeWidth: 1,
ease: Circ.easeOut
}, 1);
tl.to(el, 4, {
strokeWidth: 0,
opacity: 0,
ease: Sine.easeOut
});
},
Aber wenn eine Komponente zum ersten Mal erscheint und 30 oder mehr Elemente animiert werden, wäre es nicht mehr effizient, jedes einzelne in eine separate transition-Komponente zu wickeln. Also verwenden wir die Lifecycle-Methoden, die wir in Abschnitt 3 dieser Serie erwähnt haben, um uns in dasselbe Ereignis einzuklinken, das die Transition-Hooks unter der Haube verwenden: mounted().
const Tornadoarea = {
template: '#tornadoarea',
mounted () {
let audio = new Audio('https://s3-us-west-2.amazonaws.com/s.cdpn.io/28963/tornado.mp3'),
tl = new TimelineMax();
audio.play();
tl.add("tornado");
//tornado timeline begins
tl.staggerFromTo(".tornado-group ellipse", 1, {
opacity: 0
}, {
opacity: 1,
ease: Sine.easeOut
}, 0.15, "tornado");
...
}
};
Wir können entweder das eine oder das andere verwenden, je nachdem, was effizienter ist, und wie Sie sehen können, können Sie wirklich komplexe Effekte erzielen. Vue bietet eine wirklich schöne und flexible API, nicht nur zur Erstellung von komponierbarer Frontend-Architektur, sondern auch für flüssige Bewegungen und nahtlose Übergänge zwischen Ansichten.
Fazit
Diese Artikelreihe ist nicht als Dokumentation gedacht. Obwohl wir viel abgedeckt haben, gibt es noch so viel mehr zu entdecken: Routing, Mixins, serverseitiges Rendering usw. Es gibt so viele erstaunliche Dinge zum Arbeiten. Gehen Sie zur sehr ausgezeichneten Dokumentation und diesem Repository voller Beispiele und Ressourcen, um tiefer einzutauchen. Es gibt auch ein Buch namens The Majesty of Vue.js und Kurse auf Egghead.io.
Vielen Dank an Robin Rendle, Chris Coyier, Blake Newman und Evan You für das Korrekturlesen verschiedener Abschnitte dieser Serie. Ich hoffe, diese Serie vermittelt, warum ich so begeistert von Vue bin und hilft Ihnen, mit dem Ausprobieren einiger Materialien zu beginnen!
Artikelserie
- Rendering, Direktiven und Ereignisse
- Komponenten, Props und Slots
- Vue-cli
- Vuex
- Animationen (Sie sind hier!)
Vielen Dank, Sarah! Diese Artikel waren großartig und ergänzen sich perfekt mit der Vue-Anleitung.
Im letzten Teil erwähnten Sie die Verwendung von SASS mit Vue. Verwenden Sie SASS einfach separat oder haben Sie ein bevorzugtes SASS-Plugin für Vue? Ich habe versucht zu suchen, konnte aber keins finden.
Ich liebe es, wie Vue Stile mit seinen Komponenten gekapselt hält, aber als starker SASS-Benutzer verwalte ich meine Stile meist getrennt von Vue.
Danke!
-Eric
Hey, wenn Sie Vue-cli verwenden, um Ihr Projekt zu erstellen, ist es super einfach, Sass zu Ihren Stilen hinzuzufügen. Führen Sie einfach npm install sass sass-loader aus und fügen Sie dann lang="sass" in Ihren Style-Tags hinzu.
Körper {
background-color: red
}
Ich habe viele Beispiele für Übergänge gesehen, die für Elemente gelten, die auf dem Bildschirm erscheinen und verschwinden.
Was, wenn ich nur die Position eines Elements ändern möchte? (Es bleibt auf dem Bildschirm)
Zum Beispiel ein Seitenmenü, das sich basierend auf einem Datenwert (wahr oder falsch) einblendet.
Ich glaube, das kann durch Klassenbindung erreicht werden. Ich benutze einen "etwas ähnlichen" Effekt Ihrer Frage, aber mit einem Button-Klick. Sagen wir, meine Seitenleiste ist 20% des gesamten Bildschirms. Dann biete ich dem Benutzer die Möglichkeit, sie per Klick auf 5% zu verkleinern. Alles, was Sie brauchen, sind zwei Klassen und das Auslösen einer Klasse, wenn der Benutzer klickt. Lesen Sie hier über Klassenbindung: https://vuejs.org/v2/guide/class-and-style.html