vue3中lottie-web封装组件和api的使用

 

  使用ts的话定义类型components/Lottie/type.ts

type Segment = [ number, number]

export interface LottieEvent {
  play: () => void, // 播放动画
  pause: () => void, // 暂停动画
  stop: () => void, // 停止动画
  setSpeed: (speed: number) => void, // 设置播放速度,1 表示1倍速度,0.5 表示 0.5倍速度
  goToAndStop: (value: number, isFrame?: boolean) => void, // 跳到某一帧或某一秒停止,第二个参数 isFrame 为是否基于帧模式还是时间,默认为 false
  goToAndPlay: (value: number, isFrame?: boolean) => void, // 跳到某一帧或某一秒开始,第二个参数 isFrame 为是否基于帧模式还是时间,默认为 false
  setDirection: (direction: 1 | -1) => void, // 设置播放方向,1 表示正向播放,-1 表示反向播放
  playSegments: (segments: Segment[], forceFlag?: boolean) => void, // 播放指定的片段,参数1为数组,两个元素为开始帧和结束帧;参数2为,是否立即播放片段,还是等之前的动画播放完成
  destroy: () => void, // 销毁动画
  getDuration: (isFrames: boolean) => void,  // 获取动画时长,参数为是否基于帧模式,默认为 false. 如果为真,则返回以帧为单位的持续时间,如果为假,则以秒为单位。


  [propname: string]: any
}

// Events
// onComplete - 播放完成时触发
// onLoopComplete - 循环播放完成时触发
// onEnterFrame - 每一帧播放时触发
// onSegmentStart - 播放指定片段开始时触发

封装组件 components/Lottie/index.vue 

<script setup>
import { ref, onMounted } from 'vue'
import lottie from 'lottie-web'

// 设置组件参数
const props = defineProps({
  renderer: {
    type: String,
    default: 'svg',
  },
  // 循环播放
  loop: {
    type: Boolean,
    default: true,
  },
  autoplay: {
    type: Boolean,
    default: true,
  },
  animationData: {
    type: Object,
    default: () => ({}),
  },
  name: {
    type: String,
    default: '',
  }
})

// 创建 lottie 接收变量和获取dom
const animation = ref(null)
const dom = ref(null)

// 创建事件返回初始化lottie对象
const emits = defineEmits(['getAnimation', 'getDom'])

// 初始化渲染 lottie动画,并返回lottie对象
onMounted(() => {
  animation.value = lottie.loadAnimation({
    container: dom.value,  // 用于渲染的容器
    // 渲染方式 svg、canvas、html
    renderer: props.renderer,
    // 是否循环
    loop: props.loop,
    autoplay: props.autoplay, // 自动播放
    // UED 提供的 动画的 json 文件
    animationData: props.animationData,
    name: props.name,
  });
  emits('getAnimation', animation.value)
})
</script>

<template>
    <!-- 渲染 lottie 动画 -->
    <div id="lottieId" ref="dom"></div>
</template>

<style scoped>

#lottieId {
  width: 100%;
  height: 100%;
}

</style>

引用组件,例如HelloWord.vue

<script setup>
import { ref, onMounted, watch } from 'vue'
import Lottie from './Lottie/index.vue'
import Animation from '../assets/Animation - 1712559820721.json'
import Animation1 from '../assets/Animation-1.json'

const a1 = ref(null)
const count = ref(0)
const likeFlag = ref(false)

const getAnimation = (animation) => {
  a1.value = animation
  if (a1.value) {
    a1.value.addEventListener('enterFrame', () => {
      // console.log(a1.value, '--a1.value--');
      if (a1.value.currentFrame >= 63) { // 当前帧
        a1.value.goToAndPlay(0, true) // 跳转到指定帧开始
      }
    })
    a1.value.addEventListener('complete', () => {
      console.log('播放完毕');
    })
  }
}
const play = () => {
  if (likeFlag.value) {
    a1.value.playSegments([31, 64], true) // 播放指定的片段,([开始帧,结束帧], 是否立即播放)
  } else {
    a1.value.playSegments([0, 30], true)
  }
  likeFlag.value = !likeFlag.value
  count.value++
}

// const likeClick = () => {
//   console.log('likeClick');
//   a1.value.setSpeed(2) // 设置播放速度
//   // a1.value.setDirection(-1) // 设置播放速度,不知道什么原因这里没有生效
//   a1.value.stop()
//   setTimeout(() => {
//     // a1.value.goToAndStop(31, true) // 跳到指定帧结束,第二个参数 isFrame 为是否基于帧模式还是时间,默认为 false
//     // a1.value.goToAndPlay(21, true) // 跳转到指定帧开始
//     a1.value.play();
//   }, 100); // 延迟100毫秒播放
//   const duration = a1.value.getDuration(true) // true 为帧, false 为秒
//   console.log(duration, '--duration--'); // 64帧 2.56秒
// }

// 监听鼠标滚动事件
let frame = 0
const maxFrame = 60; // 假设最大值为100
window.addEventListener('wheel', (event) => {
  console.log(event, '--event--');
  if (event.wheelDelta < 0) {
    frame += 10
    count.value++
  } else if (event.wheelDelta >= 149) {
    frame -= 10
    count.value--
  }
  if (frame >= maxFrame) {
    frame = 0; // 重置为0
  } else if (frame < 0) {
    frame = maxFrame; // 重置为最大值
  }
  a1.value.goToAndStop(frame, true)
  console.log(frame, '--frame--');

})

onMounted(() => {
})
</script>

<template>

  <div class="card">
    <div>
      <Lottie :animation-data="Animation" />
    </div>
    <div class="card-body">
      <Lottie class="a1" :animation-data="Animation1" :loop="false" :autoplay="true" @get-animation="getAnimation"
        @click="likeClick" />
      <button @click="play">Play</button>
      <div class="count">{{ count }}</div>
      <div class="info">测试内容</div>
    </div>
  </div>

</template>

<style scoped>
.card {
  display: flex;
  align-items: center;
  width: 700px;

  /* margin: 0 auto; */
  .card-body {
    position: relative;

    .info {
      position: absolute;
      left: 50%;
      top: 20%;
      transform: translate(-50%, -50%);
      color: rgb(255, 255, 255);
    }
  }
}
</style>

 

上一篇:真实世界的密码学(三)


下一篇:设计模式-原型模式