【vue】 transitionで要素の出現や削除時にアニメーションさせる
vueでは、項目の追加、更新、削除時に、だんだん出現したりなどのトランジション効果をかんたんに付けることができます。
目次
使い方
追加や削除が発生する項目に対しトランジションをつけるには、transition
で囲みます。transition
で囲まれた要素がアニメーションをします。
<transition name="fade"> <p v-if="visible">sample</p> </transition>
transition時のアニメーションはCSSに書きます。クラス名は、{name}-enter-from
のような構成です。
つまり、transition
にname="foobar"
を設定したとすると、
foobar-enter-from
foobar-enter-to
foobar-enter-active
foobar-leave-from
foobar-leave-to
foobar-leave-active
の3つがアニメーション中に付与されます。enter
は出現時、leave
は消滅時に付与されます。
付与されるclassは、アニメーションの進行によって変化します。
v-enter-from
とv-enter-active
が付与class="v-enter-from v-enter-active"
v-enter-from
削除,v-enter-to
付与class="v-enter-active v-enter-to"
- アニメーションが終わると,
v-enter-to
とv-enter-active
削除class=""
という流れです、削除時もfrom
+active
付与→from
削除+to
付与→active
とto
削除という、同じ流れです。
from
は一瞬で消えるため、css側のtransition
でそれをアニメーション対象として指定するのが一般的です。

/* * 表示するときのアニメーション * * .xxx-enter-fromは, 表示状態になった直後に消える * .xxx-enter-activeは, 表示状態になる直前に付与され、アニメーションが終わると消える * .xxx-enter-toは, 表示状態になった直後に付与(同時にfromが消える)され, アニメーションが終わると消える */ .fade-enter-active { transition: opacity 1s ease; } .fade-enter-from { opacity: 0; } .fade-enter-to { color: #f00; } /* * 非表示にするときのアニメーション * * .xxx-leave-fromは、アニメーションが始まった瞬間に消える * .xxx-leave-activeは、非表示状態になる直前に付与され、アニメーションが終わると消える * .xxx-leave-toは、アニメーションが始まった瞬間に付与 (同時にfromが消える) され、アニメーションが終わると消える */ .fade-leave-active { transition: opacity 1s ease; } .fade-leave-from { /* opacity: 1; */ } .fade-leave-to { opacity: 0; }
See the Pen vue transition by Totori (@souki202) on CodePen.
実際のアプリケーションでうまく適用されない場合、cssの優先順位で負けている可能性があるので、セレクタを見直すと解決する可能性があります。
name
をv-bindすれば、値に応じて連動して使われるクラス名が変わるため、使用するアニメーションを簡単に切り替えることもできます。
初回描画にトランジション
要素が最初に描画されるタイミングでもトランジション可能です。appear
属性を付けます。
<transition name="fade" appear> <p>foobar</p> </transition>
v-if使用時のトランジション
例えば、次のような場合を考えてみます。
<button @click="type = (++type > 2 ? 0 : type)">表示切り替え</button> <transition name="fade"> <div v-if="type == 0" class="alert alert-success">成功</div> <div v-else-if="type == 1" class="alert alert-warning">警告</div> <div v-else-if="type == 2" class="alert alert-danger">失敗</div> </transition>
このコードでは、ボタンを押すごとに表示されるメッセージが変化する、というものです。
transition内では最初の1つの要素しか表示できません。複数の要素を表示したい場合、この後紹介するtransition-group
を用いる必要があります。
これに対し、
/* * 表示するときのアニメーション */ .fade-enter-active { transition: opacity 1s ease; } .fade-enter-from { opacity: 0; } /* * 非表示にするときのアニメーション */ .fade-leave-active { transition: opacity 1s ease; } .fade-leave-to { opacity: 0; } /* opacityはデフォルト1なので書かなくて良い */
を適用すると、次のようになります。
See the Pen vue transition2 by Totori (@souki202) on CodePen.
一瞬両方表示されますが、これは正常な挙動です。というのも、トランジション中は要素が残っており、かつ消え始めるタイミングと表示が始まるタイミングが被っているためです。
解決1: 表示位置を同じにする
これを解決するには、例えばtransition
対象にrelative
とabsolute
を用います。
つまり、3つのメッセージの位置を、absolute
を使うことで全て同じ位置にするということです。
<div class="alert-container"> <transition name="fade"> <div v-if="type == 0" class="alert alert-success">成功</div> <div v-else-if="type == 1" class="alert alert-warning">警告</div> <div v-else-if="type == 2" class="alert alert-danger">失敗</div> </transition> </div>
.alert-container { position: relative; } .alert-container > div { position: absolute; left: 0; right: 0; }
See the Pen by Totori (@souki202) on CodePen.
解決2: out-inを用いる
out-in
はtransition
のモードの1つで、消える要素が消え終わった後に、表示が始まるモードです。
<transition name="fade" mode="out-in"> ... </transition>
in-out
というモードもありまず。表示が先に始まって、それが終わったら消える要素が消え始めるというものです。あまり使いません。
デフォルトは、消え始めるのと表示が始まるのが同時です。
カスタムトランジションクラス
付与されるそれぞれのクラス名は変更することができます。この機能は、既存のCSSアニメーションライブラリと組み合わせる際に便利です。
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.0/animate.min.css" rel="stylesheet" type="text/css" /> <div id="demo"> <button @click="show = !show"> Toggle render </button> <transition name="custom-classes-transition" enter-active-class="animate__animated animate__tada" leave-active-class="animate__animated animate__bounceOutRight" > <p v-if="show">hello</p> </transition> </div>source: https://v3.ja.vuejs.org/guide/transitions-enterleave.html#css-%E3%82%A2%E3%83%8B%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3
こうすることで、.xxx-enter-active
はanimate__animated animate__tada
に置き換わります。
See the Pen Untitled by Totori (@souki202) on CodePen.
以下のクラスを置換対象にできます。
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
この機能で指定しなかったクラスは、今まで通り.xxx-enter-to
などになります。
Javascriptフック
要素のアニメーション開始時などは、Javascript側でもかんたんに検知できます。
<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>
それぞれ、vue側のmethods
に宣言します。つまり、@click
と同じようなイベントとして使えるということです。
const app = Vue.createApp({ data() { return { type: 0, }; }, methods: { /** * enter */ beforeEnter(el) { console.log(el); console.log("before enter"); }, // CSSでアニメーションを行う場合, doneの付与は自由です enter(el, done) { console.log(el); console.log("enter"); // ... done(); // CSSでアニメーション終了の役割をします }, afterEnter(el) { console.log(el); console.log("after enter"); // ... }, // 表示アニメーション中に非表示に切り替わった場合に呼ばれます enterCancelled(el) { console.log(el); console.log("enter cancelled"); // ... }, /** * leave */ beforeLeave(el) { console.log(el); console.log("before leaving"); }, // CSSでアニメーションを行う場合, doneの付与は自由です leave(el, done) { console.log(el); console.log("leave"); // ... done(); }, afterLeave(el) { console.log(el); console.log("before leaving"); // ... }, // 非表示アニメーション中に表示に切り替わった場合に呼ばれます leaveCancelled(el) { console.log(el); console.log("leave cancelled"); // ... } } });
<div class="alert alert-success">成功</div> before leaving <div class="alert alert-success">成功</div> leave <div class="alert alert-success">成功</div> before leaving <div class="alert alert-warning">警告</div> before enter <div class="alert alert-warning">警告</div> enter <div class="alert alert-warning">警告</div> after enter
:css="false"
は、CSSのアニメーションの検出をスキップする機能です。そのトランジションでCSSを利用しない場合に指定すると少し軽くなります。
done()
は, 例えば非同期通信など、一定時間後に呼びたい場合に組み合わせると便利です。
// 1秒後にdoneする enter(el, done) { setTimeout(() => { done(); }, 1000); }
まとめ
transitionは、要素の出現時と消滅時にアニメーションを行うのに便利です。v-ifを使用して複数の要素から1つだけを表示するという場合、何もしないとアニメーション中に2つ表示されるため、調整が必要です。
リストのトランジションには、transition-group
を用います、詳しくは下の記事にあります。
