Movatterモバイル変換


[0]ホーム

URL:


LoginSignup
1123

Go to list of users who liked

1085

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vue.js ( Nuxt.js ) でアニメーションやってみたら最高だった話。

Last updated atPosted at 2018-04-30

Nuxt.jsで自己紹介サイトを作りました。
https://nitta.studio/

見ていただくと分かる通りアニメーションをしまくったのですが、、

https://t.co/CXj31medDj

Nuxt.jsで自己紹介サイト作りました。NetlifyホスティングでPWA対応してます。

いろいろ自分のイカれた略歴など晒しました。宜しくお願いします。

— 新田聡一郎 (@soichiro_nitta)2018年4月26日

VuexとVue.jsのウォッチャをつかって、

  1. イベントハンドリング
  2. ステート変更
  3. ウォッチャで検知
  4. 複数のコンポーネントでアニメーション発火🔥

のような書き方をしたら最高だったので、ご紹介です。

アニメーションって、どこにどの処理書けばいいのか困りませんか?
凝ったものを実装するとめちゃめちゃなコードになりがちですよね...

しかーし!Vue.jsのデータ駆動とよばれる設計のおかげで、アニメーションの制御がとっても綺麗にできます。
(※データ駆動とは、データを中心にDOM描画をおこなったり、アクションを起こしたり、振る舞いを変えることができる設計のこと)

インタラクションが得意なデザイナ・フロントエンドさんには超おすすめですよ!

必要となる前提知識

  • Nuxt.js
  • Vue.js
  • Vuex
  • TweenMax

筆者はいつもPugとStylusを使いますが、
今回はみんな大好きHTMLSCSSでやってみますね!
てかどう考えてもPugStylusが一番いいだろ〜何でみんな嫌がるの全然意味がわからない😩

やること

Nitta.Studioのアニメーションは、解説の題材にしてはちょっと複雑なので、
簡単なサンプルを用意してみました。まずは完成形から。

2018-04-29 17.34.56.gif

  1. ボタンをクリック(イベントハンドリング)
  2. Vuexでストアのステートを変更
  3. TheLeft,TheCenter,TheRight,TheBackgroundコンポーネントのウォッチャで検知
  4. 各コンポーネントでアニメーション🔥

と、このような流れになっています。今回は順にポイントを確認していこうと思います。
サンプルコードは以下から。
https://github.com/soichiro-nitta/qiita-animation

各自cloneするなどして、

$ npm install # Or yarn install$ npm run dev # Or yarn dev

して開発環境を立ち上げてみましょう。
それでは解説していきまーす!Qiita初投稿でテンションあがってるぜフォォォ!

イベントハンドリング

まず、components/TheButton.vueを見ていきましょう。
ここでは、クリックイベントをトリガーに、ステートの変更をおこないます。
(Vuexのストアの状態を変更するのでミューテーションをコミットしています。)

components/TheButton.vue
<template><divclass='TheButton'><divclass='TheButton_Start'@click='click'<!-- メソッドを指定 -->    >

clickイベントをバインディング。

components/TheButton.vue
<script>import{mapGetters,mapMutations}from'vuex'exportdefault{// ...methods:{// ......mapMutations({click:'click'// `this.click()`にマッピングされます})}}</script>

mapMutationsヘルパーでミューテーションをマッピング。

これでクリック時にストアのミューテーションが実行されますね。

ここではclickイベントミューテーションをバインドするだけです。
ここにアニメーションのコードは書きません。

ストア

ストアはstore/index.jsで定義しています。

store/index.js
exportconststate=()=>({entered:false// このステートが変更されるとアニメーションが🔥})exportconstgetters={entered:state=>state.entered// 各コンポーネントのウォッチャで監視するので}exportconstmutations={click(state){state.entered=!state.entered// クリックされたらステートを切り替えます}}

↑ タイプclickのミューテーションは、state.enteredをトグルする形になっています。
これでクリックされたら、state.enteredが切り替わるようになりますね。

あとで説明しますが、各コンポーネントのウォッチャでは、
state.enteredが「trueになったとき」と「falseになったとき」で書き分けをしていきます。

state.enteredはウォッチャで監視するので、ゲッターも定義しておきます。

ウォッチャ

ここからが本番!
各コンポーネントのウォッチャでステートの変更を検知して、アニメーションを発火します🔥
ここではTheLeftコンポーネントのウォッチャ(watchオプション)を見てみましょう。

components/TheLeft.vue
<script>import{mapGetters}from'vuex'import{TweenMax,Expo,Elastic}from'gsap'exportdefault{// ...watch:{entered(val){// ステートの`entered`が切り替わるたび、この処理が実行されるthis.flash()// アニメーション🔥val?this.enter():this.leave()// `entered`の値によってアニメーションを書き分け🔥}},methods:{// アニメーションの宣言はここflash(){requestAnimationFrame(()=>{TweenMax.to(this.$refs.title,0.05,{// `this.$refs`でDOMにアクセスcolor:'red',scale:1.3,ease:Expo.easeIn,repeat:19,yoyo:true})})},enter(){// `entered`が`true`になったとき発火requestAnimationFrame(()=>{TweenMax.to(this.$refs.background,1,{scaleX:1,ease:Expo.easeOut})})},leave(){// `entered`が`false`になったとき発火requestAnimationFrame(()=>{TweenMax.to(this.$refs.background,1,{scaleX:0,ease:Expo.easeOut})})}}}</script>

↑ どうでしょう。綺麗じゃないですか?
ストアのenteredが切り替わるたびに、watchオプションで宣言した処理が実行されます。

筆者のおすすめは、
watchオプションにはロジックだけ書くようにして、
実際のアニメーションのコードはmethodsオプションに定義する形です。

ウォッチャに書くのはシンプルなロジックだけ!と決めておくと、汚れなくてよいと思います。

他のTheCenter,TheRight,TheBackgroundコンポーネントも同様の流れです。
要は、動かしたい対象のDOMがあるコンポーネントに、そのアニメーションも書くという設計です。
どのアニメーションがどこにあるのか、わかりやすくてイイですね!

これで今回のように、イベントハンドリングするDOMと、アニメーションしたいDOMが別コンポーネントでも、
Vuexとウォッチャのおかげで役割をハッキリさせることができました。

おまけ

async/awaitを使ったsetTimeout()の筆者オレオレmixinをご紹介。

まずは通常のsetTimeout()、こんな感じですよね?

<script>exportdefault{// ...watch:{isHell(){setTimeout(()=>{this.hell1()setTimeout(()=>{this.hell2()setTimeout(()=>{this.hell3()setTimeout(()=>{this.hell4()setTimeout(()=>{this.hell5()},500)},400)},300)},200)},100)}},// ...}</script>

ここは地獄か😇?

次に、mixinを使用したコードを見てみましょう。

<script>exportdefault{// ...watch:{asyncisHeaven(){awaitthis.$delay(100)this.heaven1()awaitthis.$delay(200)this.heaven2()awaitthis.$delay(300)this.heaven3()awaitthis.$delay(400)this.heaven4()awaitthis.$delay(500)this.heaven5()}},// ...}</script>

神じゃないですか?😻

plugins/mixin.jsにメソッドの詳細がありますので、見てみましょう。

plugins/mixin.js
importVuefrom'vue'Vue.mixin({methods:{$delay(ms){returnnewPromise(resolve=>setTimeout(resolve,ms))}}})

どうですか? これでコールバック地獄卒業しましょう。
(今回紹介しませんでしたが、TheCenter,TheRight,TheBackgroundコンポーネントでも使用しています。)

おわりに

いかがでしたでしょうか?

筆者は他のJSフレームワークも経験がありますが、
イベントハンドリング → アニメーション発火の設計には悩む場面が多く、
アニメーションどこに定義すべきか、DOMへのアクセスどうしよう、と試行錯誤の日々でした。
結局、自分ルールを作っても、できたアニメーションのコードはひどく読みづらいものでした。

しかしVue.jsを試してみると、Vuexとウォッチャのおかげで、
ロジックと、実際のアニメーションのコードを、スッキリと分けることができました!
当面はこの形に落ち着きそうだなと思っています。

また、今回はアニメーション制御の解説でしたが、
Vue初心者には、イベントハンドリングやウォッチャの使い方、Vuex、メソッド定義の設計など、いい感じに学べて、かつ視覚的にも理解がすすみそうなので、入門によい題材なのではと思います。

Vue.jsはインタラクションが得意なデザイナ・フロントエンドさんには本当にオススメなので、
ぜひ題材にしていただいて、Vue使いデザイナー・フロントエンドが増えてくれれば筆者は嬉しいです〜😸

(またTheButtonコンポーネントでは、今回トランジションを使用しましたが解説を省略しています。Vue.jsのアニメーションの真髄は、まだまだいっぱいあります。もしご興味のある方は公式ガイドでわかりやすく記されていますので、ご覧になられてはいかがでしょうか。)

1123

Go to list of users who liked

1085
11

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1123

Go to list of users who liked

1085

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?


[8]ページ先頭

©2009-2025 Movatter.jp