使用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 接收变量和获取domconst 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 = 0const maxFrame = 60; // 假设最大值为100window.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>