LottieはAirbnbが開発しているアニメーションライブラリです。
Airbnb本体のサービスにお世話になることは多分ないと思いますが(旅行行かないので…)、Lottieは非常になめらかで自由度の高いアニメーションを作ることができそうですので試してみました。
ADs
scriptタグでLottie本体を読み込みます。
1 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.6.3/lottie.min.js" type="text/javascript"></script> |
最小構成はこれだけです。
containerで指定した要素の内側にSVG(rendererオプションで「canvas」と「html」も選べます)が展開され、アニメーションが表示されます。
1 2 3 4 5 6 7 |
var submit = bodymovin.loadAnimation({ container: document.querySelector('.submitLoading'), path: 'https://assets10.lottiefiles.com/datafiles/aba45c7b75d547282b2dbdc97969412b/progress_bar.json', renderer: 'svg', loop: true, autoplay: true }); |
LottieFilesではLottieで使える様々なアニメーションが公開されています。
今回はその中で以下のものを使わせていただきました。
今回はマイクロインタラクション的な使い方を試してみます。
フォームに入力し、バリデーションに成功したらチェックマークが表示されるというものです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<div class="form-group"> <label for="tel">TEL</label> <div class="row align-items-center"> <div class="col"> <input type="text" class="form-control" :class="{ 'border-primary': validTel, 'border-danger': !validTel, }" id="tel" v-model="tel"> </div> <div class="col-auto"> <div class="valid" data-valid="tel"> </div> </div> <div class="col-12"> 電話番号のバリデーションは簡易に /^\d{2,5}[-(]\d{1,4}[-)]\d{4}$/ をtrueとしています。 </div> </div> </div> |
正規表現による電話番号のバリデーションも本気でやるととてもややこしいですので、今回は簡易に00000-0000-0000でOKとしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
//電話番号の部分だけ computed: { validTel() { var vm = this; if (vm.loadedValid) { var valid = vm.tel.match(/^\d{2,5}[-(]\d{1,4}[-)]\d{4}$/); var target = vm.validObj['tel']; if (valid) { target.setDirection(1); target.play(); return true; } else { target.setDirection(-1); target.play(); return false; } } }, }, methods: { validate() { var vm = this; var valid = document.querySelectorAll('.valid'); var valids = []; valid.forEach(function (elem, i) { valids.push( new Promise(function (resolve, reject) { vm.validObj[elem.getAttribute('data-valid')] = bodymovin.loadAnimation({ container: elem, path: 'https://assets4.lottiefiles.com/datafiles/uoZvuyyqr04CpMr/data.json', renderer: 'svg', loop: false, autoplay: false }); resolve(); }) ); }); Promise.all(valids).then(function () { vm.loadedValid = true; }); }, } |
computedが絡む場合、mountedでLottieによるアニメーションの構築が完了する前にcomputedの評価が発生してしまい、変数がundefinedになるなどのエラーが出ます。Promiseによりアニメーションの構築が完了を判定するフラグを設定するようにしています。
いいねやお気に入りなどで使えそうな、クリックしてアニメーションするハートのアイコンです。
HTMLは空のdivだけです。
1 |
<div class="like"></div> |
クリックで「liked」というクラスをトグルし、再生方向を制御しています。
実際に利用する場合はこのメソッドにいいねを保持するPOST処理が入ることになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
like() { var vm = this; var likes = document.querySelectorAll('.like'); likes.forEach(function (elem, i) { var like = bodymovin.loadAnimation({ container: elem, path: 'https://assets6.lottiefiles.com/datafiles/IhSALigao8ZXm3t/data.json', renderer: 'svg', loop: false, autoplay: false }); elem.addEventListener('click', function () { if (!elem.classList.contains('liked')) { like.setDirection(1); like.play(); elem.classList.add('liked'); } else { like.setDirection(-1); like.play(); elem.classList.remove('liked'); } }, false); }); }, |
フォームにフォーカスするとアニメーションが再生され、外れると停止します。
入力中であることを明示したり、インクリメンタルサーチなどの場合は検索結果の取得待ちのときに表示させるなどの使い方ができると思います。
1 2 3 4 5 6 7 |
<div class="form-group"> <label for="search">Search</label> <input type="text" class="form-control" id="search"> <div class="search"> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
search() { var search = bodymovin.loadAnimation({ container: document.querySelector('.search'), path: 'https://assets7.lottiefiles.com/datafiles/k8dQgGd6PgypQ3N/data.json', renderer: 'svg', loop: false, autoplay: false }); var form = document.getElementById('search'); form.addEventListener('focus', function () { search.play(); }, false); form.addEventListener('blur', function () { search.stop(); }, false); }, |
メールフォームや小さなデータの送信なら一瞬で終わるので必要のない配慮ですが、大きなデータを送信する場合は処理が進んでいることを明示したほうが親切です。
クリックしたらローディングのアニメーションが無限ループで再生され、完了したらチェックのアニメーションになるというものです。
1 2 3 4 5 6 7 8 9 10 11 |
<button class="btn btn-primary btn-block" v-on:click="submit" style="min-height: 2.5rem;"> <div v-show="submitDone == 'init'"> クリックしたらローディング(完了まで5秒ほどかかる) </div> <div v-show="submitDone == 'loading'"> <div class="submitLoading"></div> </div> <div v-show="submitDone == 'done'"> <div class="submitFinish"></div> </div> </button> |
擬似的にsetTimeoutで完了まで5秒待つということにしています。
実際はデータを送信し、Promiseのthen()やfinally()で完了と判定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
submitinit() { var vm = this; var submit = bodymovin.loadAnimation({ container: document.querySelector('.submitLoading'), path: 'https://assets10.lottiefiles.com/datafiles/aba45c7b75d547282b2dbdc97969412b/progress_bar.json', renderer: 'svg', loop: true, autoplay: true }); vm.submitFinish = bodymovin.loadAnimation({ container: document.querySelector('.submitFinish'), path: 'https://assets6.lottiefiles.com/datafiles/xagAVK6Z2hhaURL/data.json', renderer: 'svg', loop: false, autoplay: false }); }, submit() { var vm = this; vm.submitDone = 'loading'; setTimeout(function () { vm.submitDone = 'done'; vm.submitFinish.play(); }, 5000); } |
LottieFilesには総ページ数から計算したところ8500件程度のアニメーションが公開されていますが、だからと言って自サイトにぴったり合うものが必ず見つかるとは限りません。「いいね」や「カートに入れる」などの汎用的なものは問題なさそうですが、「無表情から涙を流す顔文字」みたいなものはしっくり来るものがありませんでした。
ということで、AfterEffectsの習得が直近の課題となりました。
今後のAe解説記事にご期待ください(とやらざるを得ない状況に追い込むスタイル)
ADs
コメントはまだありません。