泡の需要ない気がするけど...!
概要
業務では、どちらかというとReact.jsを触ることの方が多いのですが、たまたまコーポレートサイトでVue.jsを使う機会があったのでまとめてみました。
コーポレートサイトの見た目がちょっと寂しかったので少しアニメーションを入れてみることになり、泡をぷかぷか浮かべるアニメーションを作成してみました!
Vue.js 便利...
参考
Vue.js のドキュメントを参考にしました!
https://jp.vuejs.org/v2/guide/transitions.html
導入
transitionによる CSS アニメーション
Vue は、transition ラッパーコンポーネントを提供しています。このコンポーネントは、次のコンテキストにある要素やコンポーネントに entering/leaving トランジションを追加できます!
つまり、
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition>
<p v-if="show">hello</p>
</transition>
</div>
このように条件付きで hello と表示させる際には、enter/leave トランジションのために
v-enter,v-enter-active, v-enter-to,v-leave,v-leave-active, v-leave-to
というクラスが適用されます。
このクラスを用いて簡単にCSS トランジションを実現できるんです。
例えば
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
以上のようにcss を適用させるとトランジションのタイミングごとにクラスがふよされるのでふわっと文字が浮かび上がるアニメーションができます。
トランジション期間の設定
デフォルトではtransitionendイベントにフックすることもできますが、トランジション期間の設定をもっと明示的に設定したい場合もあるでしょう。
そんな時は、属性で JavaScript フックを定義することができます
例えば、vueファイルのtemplateで、
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
以上のように DOM イベントを読み込むために v-on ディレクティブを利用し、
// ...
methods: {
// --------
// ENTERING
// --------
beforeEnter: function (el) {
// ...
},
enter: function (el, done) {
// ...
done()
},
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
},
// --------
beforeLeave: function (el) {
// ...
},
leave: function (el, done) {
// ...
done()
},
afterLeave: function (el) {
// ...
},
// v-show と共に使うときだけ leaveCancelled は有効です
leaveCancelled: function (el) {
// ...
}
}
以上のように、メソッドをtransition内でDOM操作があった際のイベントにバインドできます。
実装
今回は2つ目の方法で実装していきます。
クリックイベントでstateが変更するようにし、
<div class="news-area" v-on:click="show = !show">
// ...
</div>
のようにクリックするとshow がtrue に変更されるようにします。
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:leave="leave"
v-bind:css="false"
>
<div class="babble" v-if="show">
<span id="babble1">●</span>
<span id="babble2">●</span>
<span id="babble3">●</span>
</div>
</transition>
vue の template内に上のように書きます。
今回は、3つの泡を同時に浮かばせて、もう一度クリックすると、3つの泡が別々の方向に飛んでいくような仕様にしました!
よってCSS は、position:absolute
をつけて泡が初めは重なるようにしました。
.babble{
position: absolute;
color: #fff;
span {
position: absolute;
}
}
javascript で、
export default {
data: function() {
return {
show: false
};
},
methods: {
beforeEnter: (el) => {
el.style.opacity = 0
el.style.left = event.pageX +'px'
},
enter: (el, done) => {
Velocity(el, { opacity: 1, fontSize: '0.9em',translateX:'8px', translateY:'-90px' }, { duration: 1000, easing: 'ease-in' })
Velocity(el, { translateX: '-8px;', translateY:'-190px' }, { duration: 700, easing: 'linear' })
Velocity(el, { translateX: '8px', translateY:'-290px' }, { duration: 1000, easing: 'ease-out' })
Velocity(el, { fontSize: '1em' }, { complete: done })
},
enterCancelled: (el) => {
Velocity(el.firstElementChild, { opacity: 0, translateX: '-8px;', translateY:'-190px', fontSize: '0.3em' }, { duration: 700, easing: 'swing' })
Velocity(el.children[1], { opacity: 0, translateX: '-98px;', translateY:'190px', fontSize: '0.3em' }, { duration: 700, easing: 'swing' })
Velocity(el.lastElementChild, { opacity: 0, translateX: '80px;', translateY:'20px', fontSize: '0.3em' }, { duration: 700, easing: 'swing' })
},
afterEnter: (el) => {
Velocity(el, { fontSize: '0.5em' }, { duration: 800, loop: 3 })
Velocity(el, { opacity: 0.8}, { duration: 800, easing: 'swing'})
},
leave: (el, done) => {
Velocity(el.firstElementChild, { opacity: 0, translateX: '-8px;', translateY:'-19px', fontSize: '0.3em' }, { duration: 700, easing: 'swing' })
Velocity(el.children[1], { opacity: 0, translateX: '-198px;', translateY:'190px', fontSize: '0.3em' }, { duration: 700, easing: 'swing' })
Velocity(el.lastElementChild, { opacity: 0, translateX: '80px;', translateY:'20px', fontSize: '0.3em' }, { duration: 700, easing: 'swing' , complete:done})
}
}
};
Velocity.js のライブラリを使用し、アニメーションをつけました。
最終的には、マウスでクリックした位置の横軸を event.pageX
で取得しその位置から泡が出るようにしました。また、クリックタイミングで自由に泡を破裂させることもできます。
こんな感じです↓
vue で泡作った pic.twitter.com/lZvmUMD1Nc
— 山田健太郎/Yamada Kentaro (@reiwaStudent) December 15, 2019
後ろの波は HTML5 の canvas 要素で作りました。
終わりに
途中、俺何してるんだろうってなりました。
楽しかったです。