LottieFilesより提供されたアニメーションをVueのComposition APIで実装する。

といっても動作させるまでに必要なことはLottie側ですべて提供されているので、コンポーネント側ではそのアプリケーション用としての共通化を図りたい。
まずは以下のソースコードが完成形。

<!-- Animation.vue -->

<template lang="html">
  <div
    ref="container"
    :style="styleObject"
    @click.stop="emitClick"
  />
</template>

<script lang="ts">
import {
  defineComponent,
  SetupContext,
  onMounted,
  Ref,
  ref,
  computed,
} from '@vue/composition-api'
import lottie, { AnimationItem } from 'lottie-web'

type Props = {
  name: string,
  loop: boolean,
  autoplay: boolean,
  width: number,
  height: number,
  src: object,
  active: boolean
  segment: [number, number]
  speed: number
}

export default defineComponent({
  props: {
    loop: {
      type: Boolean,
      default: false,
    },
    autoplay: {
      type: Boolean,
      default: false,
    },
    width: {
      type: Number,
      default: 100,
    },
    height: {
      type: Number,
      default: 100,
    },
    src: {
      type: Object,
      required: true,
    },
    active: {
      type: Boolean,
      default: false,
    },
    segment: {
      type: Array,
    },
    speed: {
      type: Number,
      default: 1
    }
  },
  setup (props: Props, context: SetupContext) {
    const animation: Ref<AnimationItem | null> = ref(null)
    const container: Ref<Element | null> = ref(null)
    const styleObject = computed(() => ({
      width: `${props.width}px`,
      height: `${props.height}px`,
    }))

    onMounted(() => {
      if (typeof container.value === 'undefined') return
      animation.value = lottie.loadAnimation({
        name: 'animation',
        container: container.value as Element,
        renderer: 'svg',
        loop: props.loop,
        autoplay: props.autoplay,
        animationData: props.src,
      })
      animation.value.setSpeed(props.speed)
      if (props.active) {
        animation.value.play()
      }
    })

    const emitClick = () => context.emit('click', animation.value)

    return {
      animation,
      container,
      styleObject,
      emitClick,
    }
  }  
})
</script>

lottie-webからインポートしたAnimationItemがアニメーションの型となり、デフォルトインポートしたlottieで初期化する。
AnimationItemにアクセスすれば大まかな指定プロパティがわかるので、それらを踏襲してpropsを定義していく。
個人的にアプリケーション内でのアニメーションに必要そうな制御としては

  • アニメーション名(個別指定にする必要はそんなにないかも)
  • 縦幅/横幅
  • 自動再生するか否か
  • ループ再生するか否か
  • レンダリングする形式
  • アニメーションファイル(JSON)
  • 再生スピード
  • セグメント(再生するフレームの始点と終点)
  • クリックイベント

ぐらいかなと考えています。

ただしこれらすべてが必要になるのは公開されたJSONを整形して使う時ぐらいで、アニメーションを作れるクリエイターがいれば、再生スピードセグメントはよしなにしてもらえる分不要になる思います。
こういう時にデザイナーのサブスキルって光る。

上記の内容を説明しておくと、まず単なるdiv要素をrefで指定できるようにしておき、マウント時にロード関数でその要素をcontainerで指定しておくとアニメーション情報と要素が紐づき、代入後のanimationで操作が可能になるという流れ。

今回はsvgでレンダリングされるように指定している。

またpropsactiveを定義しておくことによって初期表示で再生するか否かを指定する。
Webアプリとかの場合、最初から再生されるアニメーションの方が数は少ないと思うのでデフォルトはfalse
いいね機能などはクリック時に再生したいだけでなく、ある程度処理と再生を同期したいのでemitで伝番させて親で操作することにした。

ちなみに親コンポーネントの方で使う時は以下のようになる。

<template lang="html">
  <animation
    :src="likeJson"
    :width="30"
    :height="30"
    @click="handleLike"
  />
</template>

<script lang="ts">
import { defineComponent } from '@vue/composition-api'
import { AnimationItem } from 'lottie-web'
import likeJson from 'static/animation/like.json'

export default defineComponent({
  setup () {
    const handleLike = (animation: AnimationItem | null) => {
      if (animation === null) return
      animation.play()
      // 停止する場合
      animation.stop()
    }

    return {
      likeJson,
      handleLike,
    }
  }
})
</script>

参考になれば幸いです。
細かいところはうまいこと調節お願いします。
もっと洒落たやり方があれば教えてください。

プロフィール画像

ふじわら

よくわからないもので戯れてたら自分のことすらよくわからない人間になってしまいました。

ひっそりYouTubeしてます。